<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>FlowFuse</title>
    <link href="https://flowfuse.com/blog/index.xml" rel="self"/>
    <link href="https://flowfuse.com/blog"/>
    <updated>2026-04-09T00:00:00Z</updated>
    <id>https://flowfuse.com/blog</id>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/</id>
        <title>FlowFuse 2.29: FlowFuse Expert Comes to Self-Hosted Enterprise</title>
        <summary>Self-Hosted Enterprise customers can now enable FlowFuse Expert. Plus Azure DevOps Git support and clearer snapshot comparisons.</summary>
        <updated>2026-04-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/"/>
        <author><name>Dimitrie Hoekstra</name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.29 gives teams more control over how flows move through their stack, makes it easier to understand what changed between versions, and brings FlowFuse Expert to self-hosted enterprise customers.&lt;/p&gt;
&lt;h2 id=&quot;expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#expert&quot;&gt;FlowFuse Expert, Available to More Teams and More Capable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;FlowFuse Expert is our integrated AI assistant — one consistent surface across the FlowFuse website, platform, and immersive Node-RED editor for troubleshooting, building, and getting targeted help.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;expert-self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#expert-self-hosted&quot;&gt;Self-Hosted Enterprise&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Expert was previously only available to cloud customers. Self-hosted enterprise teams had no equivalent surface for in-context troubleshooting and guidance.&lt;/p&gt;
&lt;p&gt;Expert is now available for self-hosted enterprise FlowFuse instances. Your team gets the same contextual guidance and targeted help as cloud customers, with your operational data staying on your own infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/contact-us/?subject=FlowFuse%20Expert%20for%20Self-Hosted/&quot;&gt;Contact us&lt;/a&gt; to enable Expert on your self-hosted environment.&lt;/p&gt;
&lt;h3 id=&quot;expert-actions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#expert-actions&quot;&gt;Take Action Directly from Expert Responses&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Expert responses previously surfaced information and suggestions. Acting on them — importing a flow, selecting relevant nodes, opening a new tab — required switching out of the conversation and doing it manually.&lt;/p&gt;
&lt;p&gt;Expert responses can now include clickable action links. Click one and Expert performs the action directly in your editor: opening a new flow tab, selecting the nodes it just mentioned, or importing a flow from the conversation.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img style=&quot;border: 2px solid #E5E7EB;&quot; data-zoomable=&quot;&quot; alt=&quot;Expert action links demo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/expert-action-links.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Expert responses can now act on your behalf — click a link and Expert opens a tab, selects nodes, or imports a flow directly in your editor.&lt;/figcaption&gt;
&lt;p&gt;&lt;strong&gt;Coming next:&lt;/strong&gt; spinning up Node-RED instances directly from Expert, letting you go from idea to running flow without leaving the chat.&lt;/p&gt;
&lt;div class=&quot;ff-related-changelogs&quot;&gt;Changelog: &lt;a href=&quot;https://flowfuse.com/changelog/2026/04/expert-action-links/&quot;&gt;FlowFuse expert action links&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&quot;in-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#in-practice&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You act on Expert suggestions in one click instead of manually applying them&lt;/li&gt;
&lt;li&gt;You stay in the conversation while Expert works in your editor&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;deployment-workflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#deployment-workflow&quot;&gt;More Visibility and Control Across Your Deployment Workflow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing flows across environments means tracking what changed, when, and by whom. When tooling gaps introduce friction here — or leave your version control workflow fragmented — they slow teams down at exactly the wrong moment.&lt;/p&gt;
&lt;h3 id=&quot;azure-devops&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#azure-devops&quot;&gt;Azure DevOps Git Integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse&#39;s GitOps support previously required GitHub. Teams standardised on Azure DevOps had no native way to include Node-RED flows in their existing version control workflow.&lt;/p&gt;
&lt;p&gt;FlowFuse 2.29 adds Azure DevOps as a supported Git provider. You can now push and pull snapshots directly from Azure DevOps repositories using Personal Access Tokens, configured under Team Settings → Integrations.&lt;/p&gt;
&lt;h3 id=&quot;in-practice-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#in-practice-1&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You connect Azure DevOps repos alongside or instead of GitHub&lt;/li&gt;
&lt;li&gt;Your Node-RED flows participate in the same version control workflow as the rest of your stack&lt;/li&gt;
&lt;li&gt;You authenticate with Azure Personal Access Tokens, with no secondary tooling required&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;snapshot-diff&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#snapshot-diff&quot;&gt;See Exactly What Changed in a Snapshot&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse&#39;s snapshot comparison view showed flows side by side, but the visual alone doesn&#39;t always tell the whole story. You could see that a node was different, but not which specific property changed. When a function node&#39;s code changed, you couldn&#39;t identify which lines were different without manually diffing two code blocks outside of FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img style=&quot;border: 2px solid #E5E7EB;&quot; data-zoomable=&quot;&quot; alt=&quot;Snapshot diff demo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshot-comparision-view-2.29.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;The compare dialog now shows exactly which properties changed and highlights line-level differences in function code, templates, and JSON — no manual diffing required.&lt;/figcaption&gt;
&lt;p&gt;The compare dialog now includes a property-level diff sidebar: structural property changes old to new at a glance, and git-style line diffs for function code, template HTML, and JSON. A navigation bar steps through every changed, added, or deleted node with arrow key shortcuts. The canvas highlights and scrolls to the current node as you navigate.&lt;/p&gt;
&lt;h3 id=&quot;in-practice-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#in-practice-2&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You review what changed between dev and production without leaving FlowFuse&lt;/li&gt;
&lt;li&gt;You validate a teammate&#39;s update at the property level, not just the node level&lt;/li&gt;
&lt;li&gt;You debug why a flow changed after a deploy with the same tooling you use to promote it&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Expert opens by default&lt;/strong&gt;: FlowFuse Expert now opens automatically when you visit the editor for the first time. If you close it, that preference is remembered across browser sessions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedded editor tab titles&lt;/strong&gt;: Hosted and Remote Instance editor tabs now show the actual Node-RED flow name rather than a generic title.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instance URL env var&lt;/strong&gt;: Hosted Node-RED instances now expose an &lt;code&gt;FF_INSTANCE_URL&lt;/code&gt; environment variable containing the instance&#39;s URL (default or custom hostname). Useful for flows that need to know their own address, like webhook callbacks or OAuth redirects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blueprint markdown rendering&lt;/strong&gt;: Blueprint descriptions now support markdown rendering, so formatting like headers and lists display as intended.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#fixes&quot;&gt;Fixes&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP server discoverability&lt;/strong&gt;: Older MCP servers that were registered on your instances were not showing up in Expert Insights mode. All registered MCP servers are now discoverable again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snapshot detail in the immersive editor&lt;/strong&gt;: Reviewing a snapshot from inside the immersive editor now opens it in a modal, so you can inspect snapshots without leaving the editor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developer Mode tab restored in the immersive editor&lt;/strong&gt;: The Developer Mode tab is back in the immersive editor drawer, letting you toggle Auto Snapshots and create snapshots without opening a second window.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/flowfuse-release-2-29/#node-red&quot;&gt;Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-red/node-red/releases/tag/4.1.8&quot;&gt;Node-RED 4.1.8&lt;/a&gt; is now available as a stack option in FlowFuse. Highlights include function node tab badges (see at a glance which tabs contain code), theme plugin overrides for settings and menu options, configurable palette categories via theme plugins, and show-first/last-tab keyboard actions.&lt;/p&gt;
&lt;p&gt;Looking ahead, &lt;a href=&quot;https://nodered.org/blog/2025/12/03/node-red-roadmap-to-5&quot;&gt;Node-RED 5.0&lt;/a&gt; is in beta. It&#39;s a modernization and UI re-architecture that readies Node-RED for better AI-guided development and brings more clarity to manual editing. FlowFuse will ship 5.0 once it reaches stable release.&lt;/p&gt;
&lt;hr style=&quot;margin: 3rem 0; border: 0; border-top: 1px solid #D1D5DB;&quot; /&gt;
&lt;p&gt;For detailed breakdowns of each feature with additional visuals, visit our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;changelog&lt;/a&gt;. For the complete list of everything included in FlowFuse 2.29, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If something in this release improves your workflow, or if there is still friction we can remove, please &lt;a href=&quot;mailto:contact@flowfuse.com?subject=Feedback%20on%202.29/&quot;&gt;share feedback or report issues regarding this release&lt;/a&gt; to us.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/</id>
        <title>The Real Cost of Over-Engineered Industrial Systems</title>
        <summary>When the system nobody wants to touch becomes the system everything depends on</summary>
        <updated>2026-04-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;&lt;strong&gt;There is a system in your facility that your best engineer knows not to touch.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not because it&#39;s dangerous. Because the last time someone touched it, a three-hour troubleshooting session ended with a call to an integrator who no longer works at the company that built it. The system came back up. Nobody knows exactly what fixed it. The incident report says &amp;quot;configuration restored&amp;quot; and leaves it there.&lt;/p&gt;
&lt;p&gt;That system was delivered on time. It passed commissioning. The project manager closed it as a success. What it delivered, along with the data integration it was scoped to provide, was a permanent dependency on knowledge that exists nowhere formally and in fewer heads every year.&lt;/p&gt;
&lt;p&gt;This is what over-engineering looks like from inside a facility that didn&#39;t make bad decisions. It looks like a system that works, that everyone is quietly glad isn&#39;t their responsibility, and that will eventually fail in a way nobody can diagnose quickly. The complexity that created it didn&#39;t arrive as a mistake. It arrived as a series of reasonable choices made by people who weren&#39;t going to be there when the choices compounded.&lt;/p&gt;
&lt;h2 id=&quot;what-complexity-actually-costs-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/#what-complexity-actually-costs-you&quot;&gt;What Complexity Actually Costs You&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The cost shows up in three places. None of them are in the project budget.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Downtime that should take minutes takes hours.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A simple system fails in a way that matches its architecture. A Modbus timeout is diagnosable by anyone who understands the protocol. A failure inside a multi-layer stack, where data moves through a gateway, a middleware service, a message broker, and a cloud connector before it reaches its destination, has no obvious entry point. Every layer is a candidate. Every layer requires different tooling to inspect. And while the team works through them one at a time, production waits.&lt;/p&gt;
&lt;p&gt;The failure itself is often minor. The diagnostic time is what costs. And diagnostic time scales directly with architectural complexity, not with the severity of the fault.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The person who understands it becomes the system.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every complex system eventually concentrates its operational knowledge in one or two people. Not by design. By attrition. The team that inherited the system learned the parts they needed to. The parts nobody needed to touch, nobody learned. Over time, the person who has touched the most parts becomes the single point of failure the system never documented.&lt;/p&gt;
&lt;p&gt;When that person leaves, the system doesn&#39;t fail immediately. It just becomes untouchable. Problems get worked around. Upgrades get deferred. The system runs in a state of managed risk that everyone acknowledges privately and nobody escalates formally, because escalating it means admitting how fragile something critical has become.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modernization stops at the layer nobody understands.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every facility has a modernization initiative. Cloud connectivity. Real-time analytics. Unified namespace. The vocabulary changes but the ambition is consistent. What doesn&#39;t change is the conversation that happens six weeks into the scoping exercise, when the architect traces the data path and hits the layer nobody has documentation for.&lt;/p&gt;
&lt;p&gt;That layer doesn&#39;t get modernized. It gets routed around. The new system gets built on top of the old one, inheriting its limitations and adding its own. The budget meant to move the facility forward ends up funding infrastructure that looks new from the outside and runs on assumptions from 2017 underneath.&lt;/p&gt;
&lt;h2 id=&quot;simple-systems-outlive-sophisticated-ones&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/#simple-systems-outlive-sophisticated-ones&quot;&gt;Simple Systems Outlive Sophisticated Ones&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial systems are not software products. They don&#39;t get refactored on a two-week sprint cycle. They run. For years. Sometimes decades. Through shift changes, workforce turnover, firmware updates that nobody planned for, and organizational restructures that change who owns them without changing what they do.&lt;/p&gt;
&lt;p&gt;That timeline is what makes complexity so expensive in operational technology. A sophisticated architecture in a software product gets maintained by the team that built it, updated continuously, and replaced when it no longer fits. A sophisticated architecture in a plant gets handed to whoever is there three years later, maintained defensively, and never replaced, because replacement means downtime and downtime means a conversation nobody wants to have.&lt;/p&gt;
&lt;p&gt;The systems that survive this timeline are not the most capable ones. They&#39;re the most understood ones. The ones where the logic is visible, the failure modes are predictable, and the next engineer can read the configuration and understand what it does without needing to call the person who wrote it.&lt;/p&gt;
&lt;p&gt;That property, legibility, is not a soft preference. It&#39;s a hard operational requirement that almost never appears in a project specification and almost always determines whether a system ages well or becomes the thing nobody touches.&lt;/p&gt;
&lt;p&gt;Workforce turnover alone makes the case. The average tenure of an industrial automation engineer is somewhere between three and five years. The systems they build are expected to run for fifteen to twenty. Every system will be operated, maintained, and eventually modified by people who had no part in designing it. The question is whether it was built with that reality in mind, or whether it was built to impress the people in the room on the day it was commissioned.&lt;/p&gt;
&lt;h2 id=&quot;simplicity-is-an-engineering-decision&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/#simplicity-is-an-engineering-decision&quot;&gt;Simplicity Is an Engineering Decision&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consider Modbus. It has been declared obsolete for thirty years. Richer protocols have been developed, standardized, and backed by industry consortia with considerably more resources than the original Modbus specification ever had. Modbus keeps running. Not because the industry failed to move on, but because for a significant class of problems, Modbus is exactly as capable as the problem requires and no more. That match between problem and solution is not a limitation. It&#39;s the definition of good engineering.&lt;/p&gt;
&lt;p&gt;The instinct is to treat simplicity as the absence of something — less capability, less sophistication, the option you choose when budget runs out or when the team isn&#39;t skilled enough to operate something better. That instinct is wrong.&lt;/p&gt;
&lt;p&gt;Simplicity in engineering is not what you start with. It&#39;s what you arrive at. It&#39;s the outcome of understanding a problem well enough to know what it doesn&#39;t require. That&#39;s a harder position to reach than adding another integration layer, and it&#39;s a harder position to defend in a project meeting where the vendor is presenting a roadmap. But facilities that get there build systems that outlast the people who designed them — systems that new engineers can inherit without a month of archaeology, and that fail in ways the overnight technician can diagnose without calling anyone.&lt;/p&gt;
&lt;p&gt;If you&#39;re a plant manager or engineering lead looking at your current architecture, the useful question isn&#39;t &amp;quot;what could this system do.&amp;quot; It&#39;s &amp;quot;what does this system need to do, and what is the simplest architecture that does it reliably.&amp;quot; That question doesn&#39;t produce primitive infrastructure. It produces infrastructure your whole team can own, where new requirements can be added without excavating the past, and where five years from now the design looks like a deliberate decision rather than something that just accumulated.&lt;/p&gt;
&lt;p&gt;The facilities with the best operational track records made a specific tradeoff early. They accepted less capability at design time in exchange for more resilience over time. They built systems their whole team could own, not systems only their best engineer could explain. That tradeoff looks conservative in a project meeting. It looks correct every year after.&lt;/p&gt;
&lt;h2 id=&quot;what-a-well-matched-architecture-actually-looks-like&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/#what-a-well-matched-architecture-actually-looks-like&quot;&gt;What a Well-Matched Architecture Actually Looks Like&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A well-matched architecture is not a polite term for cheap. It is not a consolation for teams that couldn&#39;t get the budget for something better. It is a specific outcome, a system where every component earns its place, the stack matches the actual problem, and the team that operates it has complete visibility into how it works and why.&lt;/p&gt;
&lt;p&gt;In practice it looks like this.&lt;/p&gt;
&lt;p&gt;A facility has forty legacy devices on the floor. PLCs, drives, meters, sensors — most of them speaking Modbus, some speaking older serial protocols, none of them going anywhere soon because they&#39;re running processes that haven&#39;t changed and won&#39;t change. The facility needs that data upstream: a cloud historian, a SCADA system, an analytics platform the operations team has been waiting two years to get real data into.&lt;/p&gt;
&lt;p&gt;The over-engineered answer replaces the devices, or layers a complex middleware platform across all of them, or implements a protocol migration that requires specialist involvement at every stage and produces an architecture the in-house team can monitor but not truly operate.&lt;/p&gt;
&lt;p&gt;The right answer puts an edge gateway between the floor and everything above it. The gateway reads Modbus from the devices that have always spoken Modbus. It normalizes the data, applies context, and publishes it upstream over MQTT or OPC UA to whatever system needs it. The field devices keep running exactly as they always have. The modern infrastructure gets clean, structured data. The in-house team owns the entire stack because the entire stack is visible and configurable without a specialist on call.&lt;/p&gt;
&lt;p&gt;That is not a compromise. It is the correct answer for that problem. It connects legacy infrastructure to modern systems without introducing dependencies the team can&#39;t manage, without requiring production downtime to implement, and without creating a layer that becomes untouchable eighteen months after the integrator leaves.&lt;/p&gt;
&lt;h2 id=&quot;how-flowfuse-keeps-it-simple&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/why-simplicity-wins-in-iiot/#how-flowfuse-keeps-it-simple&quot;&gt;How FlowFuse Keeps It Simple&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The gateway architecture described above is not a new idea. Facilities have been running edge gateways for years. The problem has never been the concept. It has been the execution: gateways that are simple to deploy and complex to manage, that work correctly in isolation and become coordination problems at scale, that solve the connectivity challenge and create a new one around visibility, consistency, and control.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is an Industrial Application Platform built around &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; at the edge. The FlowFuse Device Agent connects to the devices that have always been on the floor — Modbus, MQTT, OPC UA, serial protocols — and publishes structured data upstream to whatever system needs it. The flow is visible. The logic is readable. An engineer who has never touched the system before can open it and understand what it does without documentation that may or may not exist.&lt;/p&gt;
&lt;p&gt;That last part matters more than any feature list. The single most expensive property of an industrial system is whether the team that inherits it can operate it confidently. FlowFuse is designed around that property. Flows are managed centrally, deployed consistently across every edge device in the facility using DevOps Pipelines, and monitored from a single place. When something changes, DevOps Pipelines push it across every device it needs to reach, with Snapshots providing version control and rollback, not through a manual process that depends on someone remembering which devices were updated and which weren&#39;t.&lt;/p&gt;
&lt;p&gt;Where teams need to build faster or debug more confidently, FlowFuse Expert, the AI built into FlowFuse and the Node-RED editor, reduces friction at the design stage, before complexity has a chance to accumulate. It works in two ways. The Chat Interface, accessible directly within the Node-RED editor, supports flow-building assistance and live operational data queries via MCP tools. The AI in Node-RED works inside the editor itself: inline code completions, flow autocomplete, a function builder, a flow explainer, JSON generation, and CSS and HTML generation for FlowFuse Dashboard. It doesn&#39;t generate complete flows from scratch, but it assists meaningfully at each step, suggesting the next node, completing a function, explaining logic that was written by someone who&#39;s no longer there. The result is less time spent on archaeology and more time spent on the work that actually moves the facility forward.&lt;/p&gt;
&lt;p&gt;The result is an architecture that connects legacy infrastructure to modern systems without adding the complexity that makes those connections fragile. The Modbus devices on the floor keep running. The cloud historian, the SCADA system, the analytics platform get the data they need in the format they expect. The in-house team owns the stack end to end because the stack was designed to be owned, not just operated.&lt;/p&gt;
&lt;p&gt;The system nobody wants to touch is built by engineers who won&#39;t be there to maintain it. The system the next engineer is glad to inherit is built by engineers who understood the difference. That&#39;s the decision FlowFuse is designed to support.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/</id>
        <title>Most Modbus Polling Setups Are Wrong — Here&#39;s How to Fix Yours</title>
        <summary>The configuration decisions made at setup time that cause problems you&#39;ll blame on hardware</summary>
        <updated>2026-04-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;&lt;strong&gt;Modbus polling looks simple. It is simple. That&#39;s the problem.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You set a scan rate, point it at a device, start reading registers, and data flows. It works. So nobody looks at it again.&lt;/p&gt;
&lt;p&gt;Except &amp;quot;working&amp;quot; and &amp;quot;working correctly&amp;quot; are different things in Modbus polling, and the gap between them is where most engineers quietly lose data, burn network bandwidth, and cause the intermittent device dropouts that get blamed on hardware.&lt;/p&gt;
&lt;p&gt;The mistakes aren&#39;t exotic. They&#39;re the same ones across almost every installation: polling everything at the same rate, ignoring timeouts, stacking too many registers into single requests, or hammering slow devices with back-to-back queries they were never designed to handle. None of these are obvious from the outside because Modbus doesn&#39;t complain. It just silently drops a frame or lets the device go quiet — and your polling stack fills in the gap by returning the last successfully read value, making the problem invisible until someone notices the data has stopped changing.&lt;/p&gt;
&lt;p&gt;This article isn&#39;t about the basics of how Modbus works. If you need that, start &lt;a href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/&quot;&gt;here&lt;/a&gt;. This is about the specific configuration decisions that separate a polling setup that stays stable for years from one that causes problems at the worst possible time. Part 1 covers the three mistakes made at commissioning. Part 2 covers what happens after the system is running.&lt;/p&gt;
&lt;h2 id=&quot;the-myth-of-the-universal-scan-rate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/#the-myth-of-the-universal-scan-rate&quot;&gt;The Myth of the Universal Scan Rate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every Modbus polling setup has a scan rate. Most setups have one scan rate. That&#39;s where the trouble starts.&lt;/p&gt;
&lt;p&gt;The default in most SCADA systems, Node-RED flows, and industrial gateways is to configure a single polling interval and apply it uniformly across every register on every device. 500ms. 1 second. 5 seconds. Pick a number, apply it everywhere, call it done. It&#39;s the configuration decision that takes thirty seconds and then gets inherited by every engineer who touches the system after you.&lt;/p&gt;
&lt;p&gt;The problem isn&#39;t the interval you picked. The problem is that one interval is the wrong answer for almost every real installation.&lt;/p&gt;
&lt;p&gt;Consider what&#39;s actually living in a typical Modbus device: a temperature reading that changes slowly over minutes, a motor running-hours counter that increments once per hour, an alarm status bit that can flip in under a second, and a setpoint register that only changes when an operator touches it. These are not the same kind of data. Polling all of them at the same rate means you&#39;ve optimized for nothing and made tradeoffs you never consciously chose.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polling too fast punishes your bus and your devices.&lt;/strong&gt; RS-485 is a shared medium. Every query you send to one device occupies the bus for the duration of that transaction: the request frame, the device processing time, and the response frame. On a 9600 baud network with 20 devices, a 500ms scan rate across all of them isn&#39;t 500ms per device. It&#39;s a queue. If each transaction takes 50ms, your 20-device poll cycle takes a full second to complete, which means the data you&#39;re getting from device 20 is already a second stale before you even start the next cycle. Slow sensors get polled ten times before their value could possibly have changed. Fast-changing signals still get missed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polling too slow loses events.&lt;/strong&gt; A motor fault flag that goes high for 800ms and then clears on its own will be completely invisible to a 1-second polling interval. Not occasionally invisible, reliably invisible. The bit flipped, the motor logged an internal fault, the fault self-cleared, and your polling cycle saw nothing but normal values on both sides of the event. You&#39;ll hear about that fault months later when the motor fails completely and maintenance pulls the device logs.&lt;/p&gt;
&lt;p&gt;The fix isn&#39;t complicated, but it requires making a deliberate decision you&#39;ve probably been deferring: &lt;strong&gt;categorize your data by how fast it actually changes, then assign poll rates to match.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A practical starting framework for most industrial installations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fast (100 to 500ms):&lt;/strong&gt; Alarm and fault status bits, safety interlocks, process variables driving closed-loop control. These are registers where a missed state change has operational or safety consequences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Normal (1 to 5 seconds):&lt;/strong&gt; Running process values such as flow rates, pressures, temperatures, and current draws. These change continuously but not instantaneously. A 2-second poll captures meaningful trends without hammering the bus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slow (30 seconds to 5 minutes):&lt;/strong&gt; Accumulated counters, runtime hours, setpoints, device configuration registers. These either change by operator action only or accumulate so slowly that polling them fast is pure waste.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On-demand only:&lt;/strong&gt; Nameplate data, firmware versions, serial numbers, calibration constants. Poll once at startup and cache. Never poll again during normal operation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This tiered approach does something important beyond just reducing bus load: it aligns your polling architecture with the operational reality of the process you&#39;re monitoring. An engineer reading your configuration can look at the scan rates and immediately understand which signals the system treats as critical and which it treats as background. That&#39;s information that doesn&#39;t exist in a flat 1-second-everything setup.&lt;/p&gt;
&lt;p&gt;The pushback you&#39;ll hear is that tiered polling is harder to configure and harder to document. That&#39;s true. A single scan rate is simple to explain and simple to hand off. But simple to configure and correct are different things, and a polling architecture that silently misses events or saturates a serial bus isn&#39;t simple. It&#39;s a problem that hasn&#39;t surfaced yet.&lt;/p&gt;
&lt;p&gt;One more thing worth stating plainly: your scan rate has to account for the device&#39;s actual response capability, not just the rate you want data. Some field devices, including older PLCs, low-cost sensors, and anything running on an 8-bit microcontroller with slow UART handling, need 50 to 150ms just to process a request and formulate a response. If your fast-tier scan rate is 100ms and your device needs 120ms to respond, you&#39;re not getting 100ms data. You&#39;re getting collisions, timeouts, and a maintenance headache. Measure actual device response times before setting your fast-tier interval. The device datasheet will give you a starting point; a protocol analyzer will give you the truth.&lt;/p&gt;
&lt;h2 id=&quot;how-timeout-misconfiguration-kills-stability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/#how-timeout-misconfiguration-kills-stability&quot;&gt;How Timeout Misconfiguration Kills Stability&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Timeouts are the most quietly destructive configuration parameter in a Modbus polling setup. Set them wrong and your system doesn&#39;t fail loudly. It just becomes unreliable in ways that are genuinely difficult to trace back to the source.&lt;/p&gt;
&lt;p&gt;Here&#39;s what actually happens when a Modbus master sends a request: it waits. There&#39;s no explicit acknowledgment mechanism beyond the response itself, no &amp;quot;I got your request, give me a moment.&amp;quot; The master sends the frame and sits in silence until either a valid response arrives or the timeout expires. What happens after that expiry, whether retry, skip, error, or log, is entirely up to whatever stack you&#39;re using. Modbus itself has no opinion.&lt;/p&gt;
&lt;p&gt;That silence is where most setups go wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The too-tight timeout problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The instinct when configuring timeouts is to set them aggressively short. Short timeouts mean fast failure detection. Fast failure detection means the polling cycle doesn&#39;t stall when a device goes quiet. That logic is correct in theory and damaging in practice.&lt;/p&gt;
&lt;p&gt;The issue is that &amp;quot;device response time&amp;quot; isn&#39;t a fixed number. It varies. A device that normally responds in 40ms might take 90ms when its processor is busy handling an internal alarm condition. It might take 130ms during a firmware-driven self-diagnostic that runs every few hours. It will almost certainly take longer under electrical noise conditions where the first frame gets corrupted and the device is waiting for a valid request that never arrives cleanly.&lt;/p&gt;
&lt;p&gt;If your timeout is 100ms and your device occasionally needs 130ms, you get a spurious timeout. The master marks the request as failed and moves on to the next poll. The device, meanwhile, finishes processing and transmits a perfectly valid response — but the master has already abandoned that transaction. Those late bytes now sit in the master&#39;s receive buffer. When the next legitimate response arrives, those orphaned bytes are still there, and the master&#39;s parser reads a combined stream of garbage from both, corrupting the next response and producing another error. On RS-485 networks this compounds faster than on TCP because there&#39;s no underlying transport layer to absorb or sequence the damage. One misconfigured timeout on one device can introduce intermittent errors across the entire bus segment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Calculating a timeout that actually makes sense&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Timeout values aren&#39;t arbitrary. They have a floor set by physics and firmware, and your configured value needs to sit above that floor with enough margin to absorb real-world variation. The floor has three components:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Transmission time&lt;/em&gt; is how long it takes to physically clock the request frame onto the wire. At 9600 baud, each bit takes roughly 104 microseconds. A typical Modbus RTU request runs 8 bytes, which at 11 bits per byte (1 start bit, 8 data bits, 1 stop bit, plus parity) comes to roughly 88 bits, so about 9ms just to transmit at 9600 baud. At 19200 baud it halves. At 115200 baud it becomes negligible.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Device processing time&lt;/em&gt; is how long the device takes to receive the complete request, validate the CRC, look up the register values, and build the response. Budget 20 to 50ms for most industrial devices, 50 to 100ms for older PLCs and slower microcontrollers, and up to 150ms for devices known to have slow UART handling.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Response transmission time&lt;/em&gt; is the time to clock the response frame back. A read response for 10 registers runs about 25 bytes, roughly 25ms at 9600 baud.&lt;/p&gt;
&lt;p&gt;Add those up for a 9600 baud network reading 10 registers from a moderately slow device: 8ms transmit + 75ms processing + 25ms response = 108ms minimum. A 100ms timeout fails this transaction every time. A 150ms timeout passes it usually but fails it when the device is under load. A 250ms timeout gives you real margin.&lt;/p&gt;
&lt;p&gt;The general rule: calculate your floor, then multiply by 1.5 to 2 as a stability margin. That margin isn&#39;t wasted time. It&#39;s the difference between a system that runs cleanly for years and one that produces unexplained errors every few days. For Modbus TCP the math changes but the principle doesn&#39;t. TCP eliminates the baud rate component, but device processing time still dominates, and now you&#39;ve added network latency and TCP stack overhead on both ends. A 500ms timeout is reasonable for most TCP deployments. Anything under 200ms can lead to intermittent failures depending on device response time and network conditions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The too-loose timeout problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The other failure mode gets less attention because it doesn&#39;t cause errors. It causes slowness, which is easier to ignore.&lt;/p&gt;
&lt;p&gt;A timeout set at 5 seconds on a serial network means every unresponsive device costs you 5 seconds of dead time per poll cycle. If you have 3 offline devices on a 20-device bus, you&#39;re burning 15 seconds per cycle waiting for responses that will never come. This is particularly common in systems that were built to poll 20 devices and are now down to 12 because equipment was removed without anyone updating the polling configuration. The device list grows stale, the timeouts fire on phantom addresses, and the cycle time balloons silently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Retries: the configuration that multiplies your problems&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most Modbus stacks let you configure a retry count. The default in many tools is 3. That sounds conservative. It isn&#39;t.&lt;/p&gt;
&lt;p&gt;Three retries at a 250ms timeout means a single unresponsive device costs you 1 full second per poll cycle before the master gives up and moves on. On a fast-tier signal you&#39;re trying to poll at 500ms, one bad device makes your entire fast-tier effectively useless. The right retry count for most industrial installations is 1, sometimes 2. A single retry catches genuine transient errors. Multiple retries on a serial bus create the congestion that causes the errors you&#39;re trying to catch. Set your timeout correctly and you need fewer retries. Set your timeout too tight and no retry count will save you.&lt;/p&gt;
&lt;h2 id=&quot;register-batching%3A-do-it-right-or-don&#39;t-do-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/#register-batching%3A-do-it-right-or-don&#39;t-do-it&quot;&gt;Register Batching: Do It Right or Don&#39;t Do It&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Register batching is the Modbus optimization that every engineer knows about and most engineers get half right. The concept is simple: instead of sending ten separate read requests for ten individual registers, send one request that reads a contiguous block covering all ten. One transaction instead of ten. One round-trip instead of ten. The bus thanks you.&lt;/p&gt;
&lt;p&gt;What gets left out of that explanation is the word &lt;em&gt;contiguous&lt;/em&gt;, and that omission is where batching goes from optimization to problem.&lt;/p&gt;
&lt;p&gt;Every Modbus transaction carries fixed overhead regardless of how many registers you&#39;re reading. On a 9600 baud RS-485 network, a single-register read transaction takes roughly 10ms in transmission time alone. Reading 50 registers one at a time: potentially 500ms or more in wire time. Reading those same 50 registers in one batched request: one transaction, maybe 30ms. The efficiency difference isn&#39;t marginal. It&#39;s an order of magnitude.&lt;/p&gt;
&lt;p&gt;The advice to batch your reads is correct. The problem is what happens when engineers apply it without reading the register map first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The contiguous register requirement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Modbus function code 03 reads a starting address plus a quantity, that block, sequentially, with no gaps. If you want registers 40001, 40050, and 40099, you cannot batch those in one request. You need three separate requests, or you read the entire range from 40001 to 40099 and discard the 96 registers you don&#39;t need.&lt;/p&gt;
&lt;p&gt;That second option is where the mistake happens. Engineers conclude that reading a larger block is always better than reading a smaller one. So they batch aggressively: read registers 40001 through 40200 in one shot and parse out the handful of values they actually need.&lt;/p&gt;
&lt;p&gt;This works fine until you hit a gap in the register map containing a reserved or unimplemented register. Modbus devices are not required to return valid data for registers that aren&#39;t defined in their implementation. Many return zero. A significant number return an exception response, Modbus error code 02 (illegal data address), which terminates the entire read request and returns nothing. Your aggressive batch that was supposed to read 50 useful values returns an exception because register 40047 isn&#39;t implemented on this firmware version, and now you have no data from any of those 50 registers until the next poll cycle.&lt;/p&gt;
&lt;p&gt;This is one of the most common sources of intermittent data gaps in Modbus installations. The polling works fine during commissioning on a bench setup, then produces sporadic errors in the field when devices from a different firmware revision have slightly different register implementations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to batch correctly&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Start with the device register map from the vendor documentation. Read it to understand the layout, not just to find the registers you want. Where are the gaps? Which registers are reserved? Which are only valid in certain operating modes?&lt;/p&gt;
&lt;p&gt;Then group registers into contiguous or near-contiguous clusters where the gap between any two consecutive needed registers is small, using 10 registers or fewer as a starting heuristic. Each cluster becomes one batch request. Clusters separated by larger gaps become separate requests.&lt;/p&gt;
&lt;p&gt;For a device where you need registers 40001–40010, 40015–40020, and 40100–40110: the first two clusters are close enough that one request covering 40001 to 40020, reading 20 registers and wasting 5, is acceptable. The third cluster at 40100 is 80 registers away. That&#39;s a separate request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Batching and your poll rate tiers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If your fast-tier registers are scattered through the same address space as your slow-tier registers, batching them together means polling slow registers at your fast rate, which defeats the tiering entirely. Design your batches per tier. Fast-tier batch: only fast-tier registers, polled at your fast interval. Slow-tier batch: only slow-tier registers, polled at your slow interval. If registers from different tiers happen to be contiguous in the address map, resist the temptation to merge them. A slightly less efficient batch that preserves your polling architecture is better than an efficient batch that collapses your scan rate strategy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A note on writes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Function code 16 allows batching writes the same way FC03 batches reads. But write batching carries a risk read batching doesn&#39;t: a single malformed batch can corrupt multiple independent settings simultaneously. For writes, err toward smaller, focused transactions even at the cost of bus efficiency. When you&#39;re writing to a live device controlling an active process, the reliability argument outweighs the performance argument.&lt;/p&gt;
&lt;h2 id=&quot;where-this-leaves-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/04/modbus-polling-best-practices/#where-this-leaves-you&quot;&gt;Where This Leaves You&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The three problems this article covers, scan rate uniformity, timeout miscalculation, and aggressive batching, share a common trait: none of them produce an immediate, obvious failure. They produce a system that works, mostly, until it doesn&#39;t. The errors they cause get blamed on hardware, on electrical noise, on the device vendor. The actual cause sits in a configuration file that nobody has looked at since commissioning.&lt;/p&gt;
&lt;p&gt;The fix for all three is the same kind of work: deliberate, once, documented. Tier your scan rates to match how fast your data actually changes. Calculate your timeouts from the physics of your network rather than accepting defaults. Read the register map before you batch. None of this takes long. None of it requires downtime. It just requires treating these as decisions rather than defaults.&lt;/p&gt;
&lt;p&gt;If you&#39;ve made these changes and your installation is still misbehaving, the problem is in the operational layer: how your polling architecture handles the network and devices once they&#39;re running. That&#39;s what Part 2 covers: serial versus TCP failure modes, unresponsive device handling, live diagnostics, and how to fix what you find without taking production down.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/</id>
        <title>Why OPC UA Is Not Replacing Modbus (Yet)</title>
        <summary>Why your next device will still ship with Modbus, and what OPC UA needs to fix before that changes</summary>
        <updated>2026-03-30T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;&lt;strong&gt;Everyone in industrial automation agrees: OPC UA is the future. The specs are richer. The security is real. The semantic modeling is genuinely elegant. The industry consortia say so. The whitepapers say so. Vendors say so constantly, especially the ones selling OPC UA stacks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modbus is still winning.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not in keynotes. Not in roadmaps. On the factory floor, in new device datasheets, in RFQs sent out this quarter, Modbus keeps showing up where OPC UA was supposed to have taken over by now.&lt;/p&gt;
&lt;p&gt;In January, we wrote about &lt;a href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/&quot;&gt;why Modbus refuses to die&lt;/a&gt; — the installed base, the zero-cost implementation, the vendor neutrality, the brutal simplicity that makes it work at 3 AM when nothing else will. That piece hit a nerve. The responses fell into two camps: engineers who nodded along because they live this every day, and architects who pushed back insisting OPC UA adoption is accelerating.&lt;/p&gt;
&lt;p&gt;Both camps are right. And that&#39;s exactly the problem.&lt;/p&gt;
&lt;p&gt;OPC UA isn&#39;t losing because it&#39;s a bad protocol. It&#39;s losing ground in places it should dominate because the gap between what OPC UA &lt;em&gt;can&lt;/em&gt; do and what most facilities &lt;em&gt;need&lt;/em&gt; done remains wider than the standards bodies want to admit. Capability isn&#39;t the same as adoption. A Ferrari doesn&#39;t win in a parking lot.&lt;/p&gt;
&lt;p&gt;This isn&#39;t a eulogy for OPC UA. It&#39;s a sober look at the structural reasons why a protocol with every technical advantage on paper hasn&#39;t delivered the displacement its advocates have been predicting for fifteen years, and what would actually need to change for the &amp;quot;yet&amp;quot; in that title to disappear.&lt;/p&gt;
&lt;h2 id=&quot;the-promise-vs.-the-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#the-promise-vs.-the-reality&quot;&gt;The Promise vs. The Reality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA was ratified in 2008. That&#39;s eighteen years ago. The pitch was compelling: a unified, secure, semantically rich protocol that would finally bring industrial automation into the modern era. The OPC Foundation had vendor backing. The specification was thorough. The vision was clear.&lt;/p&gt;
&lt;p&gt;Optimistic predictions followed. The expectation in many quarters was that by the mid-2010s OPC UA would be the dominant machine-level protocol, that Modbus would be a legacy concern by 2020, and that the transition would be essentially complete by the middle of this decade. Those expectations reflected genuine enthusiasm for the protocol&#39;s capabilities, not sourced forecasts — but they shaped investment decisions and roadmaps across the industry nonetheless.&lt;/p&gt;
&lt;p&gt;None of that happened.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.futuremarketreport.com/industry-report/modbus-communication-module-market&quot;&gt;Modbus TCP market was valued at $1.35 billion in 2024 and is projected to reach $2.55 billion by 2032&lt;/a&gt;. That isn&#39;t legacy drag. That&#39;s active investment. New Modbus devices are being designed, manufactured, purchased, and installed in 2026, not as fallback options, but as deliberate first choices. Meanwhile, OPC UA adoption, while genuinely growing, remains concentrated in specific layers of the automation stack: SCADA systems, MES integrations, and IT/OT gateways. At the field device level, Modbus still dominates.&lt;/p&gt;
&lt;p&gt;The gap between expectation and reality isn&#39;t a failure of OPC UA&#39;s design. The protocol does what it promises. The gap exists because adoption in industrial automation doesn&#39;t follow software industry timelines. A protocol doesn&#39;t win by being technically superior. It wins by becoming the path of least resistance across every layer of the ecosystem simultaneously: device manufacturers, integrators, maintenance teams, procurement departments, and plant managers all have to move together. That has never happened with OPC UA, and understanding why requires looking at each layer honestly.&lt;/p&gt;
&lt;h2 id=&quot;the-complexity-tax-nobody-talks-about&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#the-complexity-tax-nobody-talks-about&quot;&gt;The Complexity Tax Nobody Talks About&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA&#39;s biggest competitor isn&#39;t Modbus. It&#39;s its own specification.&lt;/p&gt;
&lt;p&gt;The full OPC UA specification runs across fourteen separate documents. A developer picking up Modbus for the first time can read the entire protocol specification over a weekend and ship a working implementation by Monday. A developer picking up OPC UA faces months of study before they can confidently build something production-ready.&lt;/p&gt;
&lt;p&gt;This isn&#39;t an unfair criticism. It&#39;s the honest cost of doing more. Modbus reads and writes registers. OPC UA models information, manages sessions, handles subscriptions, enforces security policies, and describes data with rich metadata. That capability has a price, paid in implementation time, developer hours, and operational complexity.&lt;/p&gt;
&lt;p&gt;For device manufacturers, the math is punishing. A Modbus RTU interface costs roughly $5 to $10 in silicon and a few days of firmware work. A proper OPC UA server, implemented correctly with certificate management, secure channels, and a meaningful information model, requires a capable processor, sufficient memory, and weeks of engineering time. For a sensor company shipping into a price-sensitive market, that difference doesn&#39;t show up as a line item in the spec sheet. It shows up in whether the product gets built at all.&lt;/p&gt;
&lt;p&gt;Certificate management alone has quietly killed more OPC UA deployments than any technical limitation. Certificates expire. They need to be provisioned, rotated, and trusted across every client and server. In an IT environment with dedicated security teams, this is manageable. In a plant where the automation engineer also handles PLC programming, HMI design, and network troubleshooting, it becomes an ongoing burden that nobody budgeted for and nobody wants to own.&lt;/p&gt;
&lt;p&gt;The OPC Foundation recognized this. Companion specifications like OPC UA FX and the Field Level Communications initiative are genuine attempts to bring the protocol closer to the field device layer. Progress is real but slow, and in the meantime, device manufacturers continue defaulting to Modbus because it ships today without a compliance checklist.&lt;/p&gt;
&lt;p&gt;Complexity isn&#39;t a dealbreaker when the problem demands it. Nobody complains that OPC UA is too complex when it&#39;s modeling an entire production line in a SCADA system. The complexity tax only becomes fatal when the problem is simple and a simpler tool is sitting right there, already understood by the team, already working.&lt;/p&gt;
&lt;h2 id=&quot;the-skills-gap-on-the-floor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#the-skills-gap-on-the-floor&quot;&gt;The Skills Gap on the Floor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Protocols don&#39;t run themselves. People configure them, troubleshoot them, and fix them at 2 AM when production is down. And the people doing that work in most manufacturing facilities today learned Modbus, not OPC UA.&lt;/p&gt;
&lt;p&gt;This isn&#39;t a generational complaint. It&#39;s a workforce reality with direct operational consequences. The automation technician who has spent fifteen years on a plant floor can read a Modbus register map the way a mechanic reads an engine. They know register 40023 on device 12 is the motor temperature. They know what value triggers an alarm. They know how to pull up a protocol analyzer and spot the problem in minutes.&lt;/p&gt;
&lt;p&gt;Ask that same technician to troubleshoot an OPC UA subscription that stopped delivering updates and the confidence evaporates. Is it a certificate issue? A session timeout? A misconfigured sampling interval? A namespace problem? The diagnostic path is longer, the tooling is more complex, and the required knowledge base is fundamentally different. The problem gets escalated, production stays down longer, and the experience gets filed away as evidence that OPC UA is unreliable. The protocol isn&#39;t unreliable. The skills to operate it confidently just aren&#39;t evenly distributed yet.&lt;/p&gt;
&lt;p&gt;Training helps but doesn&#39;t solve the structural problem. OPC UA expertise is concentrated in system integrators and automation vendors, not in the maintenance teams who keep plants running day to day. Facilities that have gone deep on OPC UA often find themselves dependent on a small number of people who truly understand the stack, creating exactly the kind of single point of failure that conservative plant managers spend their careers avoiding.&lt;/p&gt;
&lt;p&gt;The skills gap will close eventually. Engineering curricula are adding industrial networking content. Younger engineers are entering the field with broader protocol exposure. But eventually in industrial automation means a decade, not a release cycle. The plants being designed today will be maintained by the workforce that exists today, and that workforce is fluent in Modbus in a way it simply isn&#39;t in OPC UA yet.&lt;/p&gt;
&lt;h2 id=&quot;the-hardware-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#the-hardware-reality&quot;&gt;The Hardware Reality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus RTU was designed in 1979 for the hardware constraints of 1979 — worth noting that Modbus TCP, the networked variant that dominates modern installations, didn&#39;t arrive until 1999. But the original serial protocol&#39;s frugality is what set the expectation, and the ecosystem never abandoned it.&lt;/p&gt;
&lt;p&gt;A bare-minimum Modbus RTU slave implementation can run on an 8-bit microcontroller with around 10KB of flash and 1.5KB of RAM. A robust, production-grade implementation with full error handling and edge-case coverage needs more — typically several times that — but the floor is still extremely low compared to almost any alternative. Device manufacturers building sensors, meters, drives, and actuators work within tight BOM constraints where every dollar multiplies across thousands of units. Modbus fits inside the microcontroller they were already using. It adds no hardware cost and minimal firmware complexity.&lt;/p&gt;
&lt;p&gt;OPC UA has a different story. A properly implemented OPC UA server needs a real processor capable of running a TCP/IP stack, handling cryptographic operations, and managing runtime memory requirements. Lightweight stacks like open62541 have brought the floor down meaningfully — a constrained OPC UA server can run in under 100KB of flash with careful implementation — but that still represents a significant step up from a Modbus RTU slave, and a full-featured server with a rich information model typically requires several hundred kilobytes of RAM or more.&lt;/p&gt;
&lt;p&gt;The OPC Foundation&#39;s work on OPC UA FX targets exactly this problem, aiming to bring the protocol down to devices with 256KB of flash and 64KB of RAM. That&#39;s genuine progress. It&#39;s also still an order of magnitude more resource-intensive than a minimal Modbus implementation on equivalent hardware, and FX-capable devices are only beginning to reach the market.&lt;/p&gt;
&lt;p&gt;For established device categories the cost difference compounds quickly. A manufacturer selling thousands of flow meters into water treatment, oil and gas, and chemical processing isn&#39;t just buying components. They&#39;re buying tooling, certifications, and support infrastructure built around specific hardware platforms. Changing the processor family to support OPC UA means requalifying the entire product, retesting for environmental and EMC compliance, and retraining field service teams. The protocol upgrade triggers a full product redesign, and the business case rarely pencils out when the existing Modbus version is selling reliably into a market that hasn&#39;t asked for OPC UA.&lt;/p&gt;
&lt;p&gt;Until OPC UA can run comfortably on the same class of hardware Modbus runs on today, at comparable cost and without requiring a platform redesign, the field device market will continue defaulting to Modbus. Not because engineers prefer old technology, but because the economics of building physical hardware into conservative industrial markets leave very little room for protocol idealism.&lt;/p&gt;
&lt;h2 id=&quot;where-opc-ua-actually-wins&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#where-opc-ua-actually-wins&quot;&gt;Where OPC UA Actually Wins&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This isn&#39;t a one-sided argument. OPC UA dominates in specific contexts and deserves the credit it gets there. Conflating the two is how bad architecture decisions get made in both directions.&lt;/p&gt;
&lt;p&gt;At the SCADA and MES layer, OPC UA is the right answer. When you need to aggregate data from hundreds of heterogeneous devices and feed it into manufacturing execution systems, historian databases, and enterprise analytics platforms, Modbus gives you registers with no context. OPC UA gives you structured, self-describing data with units, ranges, relationships, and meaning baked in. At scale, that semantic layer saves thousands of engineering hours.&lt;/p&gt;
&lt;p&gt;Security requirements close the conversation quickly. The moment a system needs to be accessible from outside the plant network, Modbus is disqualified. Not because it can&#39;t be hardened with compensating controls, but because its security model is nonexistent by design. OPC UA with TLS encryption, certificate-based authentication, and role-based access control provides the foundation connected industrial systems actually need.&lt;/p&gt;
&lt;p&gt;Large equipment builders and machine OEMs increasingly ship with OPC UA as the primary integration interface, for good reason. A packaging line, CNC machining center, or industrial robot is a complex asset with hundreds of meaningful data points. OPC UA companion specifications from industry groups like OMAC, EUROMAP, and the VDMA define standardized information models for entire equipment categories. A machine built to the PackML OPC UA companion spec integrates with any PackML-aware SCADA system without custom mapping work. That interoperability has real commercial value.&lt;/p&gt;
&lt;p&gt;Greenfield installations with modern hardware and no legacy constraints are where arguments for Modbus at the field level are weakest. When the BOM can absorb the hardware cost and the team has OPC UA skills, there is no compelling reason to default to a register-based polling protocol from 1979.&lt;/p&gt;
&lt;p&gt;The pattern is consistent. OPC UA wins where complexity is justified by the problem, where security is non-negotiable, and where people and hardware resources exist to implement it properly. Those conditions describe the upper layers of the automation stack and modern greenfield projects. They do not yet describe the majority of the field device layer, and that distinction is exactly why the &amp;quot;yet&amp;quot; still belongs in this article&#39;s title.&lt;/p&gt;
&lt;h2 id=&quot;the-gateway-middle-ground&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#the-gateway-middle-ground&quot;&gt;The Gateway Middle Ground&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The industry didn&#39;t wait for OPC UA to win. It built a workaround and quietly made it the standard architecture.&lt;/p&gt;
&lt;p&gt;Edge gateways now sit at the boundary between the field device layer and everything above it, speaking Modbus to the equipment that has always spoken Modbus and presenting OPC UA, MQTT, or REST to the systems that need structured, secure data. It isn&#39;t a temporary fix pending full OPC UA adoption. For most facilities, it is the architecture, and it works well enough that the pressure to replace Modbus at the source has largely evaporated.&lt;/p&gt;
&lt;p&gt;This reflects how industrial modernization actually happens. Plants don&#39;t replace working equipment to adopt better protocols. They add intelligence at the edge and leave the field devices alone. A Modbus temperature transmitter installed in 2008 keeps transmitting exactly as it always has. The gateway reads its registers, maps the raw value to a properly typed OPC UA node with engineering units and metadata attached, and publishes it upstream. The transmitter never knows the difference. The SCADA system gets clean, contextualized data. Nobody touched the wiring.&lt;/p&gt;
&lt;p&gt;The business case is straightforward. Replacing field devices across a large facility to gain native OPC UA at the source costs millions of dollars, requires production downtime, and delivers no improvement in the process being controlled. Adding an edge gateway costs thousands, takes days to deploy, and delivers the same data quality improvement. The ROI calculation ends quickly.&lt;/p&gt;
&lt;p&gt;FlowFuse is built around exactly this architecture. Node-RED flows running on the edge read Modbus registers from legacy field devices, apply context and normalization, and publish structured data over MQTT or OPC UA to cloud systems, historians, and analytics platforms. The Modbus equipment keeps running. The modern data infrastructure gets what it needs. The migration happens at the connectivity layer rather than the device layer, which is the only migration path that makes economic sense for most operational facilities.&lt;/p&gt;
&lt;p&gt;The gateway middle ground isn&#39;t a compromise born of failure. It&#39;s a pragmatic recognition that the automation stack has always been heterogeneous and always will be. New protocols don&#39;t replace old ones in industrial environments. They get added on top, and the translation layer between them becomes the most important piece of architecture in the building.&lt;/p&gt;
&lt;h2 id=&quot;what-would-actually-accelerate-opc-ua-adoption&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#what-would-actually-accelerate-opc-ua-adoption&quot;&gt;What Would Actually Accelerate OPC UA Adoption&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Diagnosing why OPC UA hasn&#39;t replaced Modbus is useful. Identifying what would actually change the trajectory is more useful. Not wishlist thinking, but a realistic assessment of the specific friction points that, if addressed, would move the needle in ways that eighteen years of industry advocacy has not.&lt;/p&gt;
&lt;p&gt;The most immediate lever is simplification at the implementation level. Device manufacturers make platform decisions years before products ship. Every year that lightweight OPC UA profiles remain incomplete or poorly supported by silicon vendors is another product generation that defaults to Modbus. Finalizing FX profiles, getting them supported in major embedded toolchains, and making reference implementations genuinely production-ready would lower the barrier in ways that specification documents alone cannot.&lt;/p&gt;
&lt;p&gt;Certificate management needs to be solved, not documented. The current approach requires automation engineers to operate like IT security professionals in environments where that expertise simply does not exist. Automated certificate lifecycle management, built into OPC UA servers and clients by default, would remove one of the most common reasons deployments stall or fail after going live. Several vendors are working on this. It needs to become a baseline expectation, not a premium feature.&lt;/p&gt;
&lt;p&gt;Open source needs to catch up. Modbus has dozens of mature, well-documented stacks across every embedded platform imaginable. OPC UA open source options have improved — open62541 in particular has become a credible foundation — but the ecosystem remains thinner and less consistent in quality and maintenance overall. A developer evaluating both protocols reaches for the option with better community support and lower risk of hitting an undocumented edge case six months before launch. Closing that gap requires sustained investment from the OPC Foundation, major vendors, and the broader industrial open source community.&lt;/p&gt;
&lt;p&gt;Interoperability between vendor implementations remains more aspirational than actual. Passing certification does not guarantee seamless interoperability across every feature combination two products might use together. Tightening conformance requirements and expanding interoperability testing infrastructure would give integrators the confidence that OPC UA devices from different manufacturers actually work together reliably, the way Modbus devices have for forty years.&lt;/p&gt;
&lt;p&gt;Finally, the total cost of ownership narrative needs to be addressed honestly. OPC UA advocates often present the protocol&#39;s benefits without fully accounting for implementation costs, support burden, and skills investment. Facilities that have been oversold and then struggled become skeptics who push back on the next modernization proposal. Engineers trust data and specifics. Give them that.&lt;/p&gt;
&lt;p&gt;None of these changes are impossible. Some are already in progress. But progress in industrial standards moves at the pace of the least motivated stakeholder, and the least motivated stakeholders are the ones who have something that works today.&lt;/p&gt;
&lt;h2 id=&quot;conclusion%3A-the-%22yet%22-has-a-deadline-%E2%80%94-but-nobody-knows-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/why-opcua-is-not-replacing-modbus-yet/#conclusion%3A-the-%22yet%22-has-a-deadline-%E2%80%94-but-nobody-knows-it&quot;&gt;Conclusion: The &amp;quot;Yet&amp;quot; Has a Deadline — But Nobody Knows It&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA will win. That part isn&#39;t in dispute.&lt;/p&gt;
&lt;p&gt;The semantic modeling is too useful to ignore forever. The security requirements of connected industrial systems are too real to patch around indefinitely. The demand for self-describing, context-rich data will only grow as analytics, AI, and remote operations become standard expectations. The protocol that delivers all of that is OPC UA, not Modbus.&lt;/p&gt;
&lt;p&gt;But winning eventually and winning now are two entirely different things. Fieldbus was supposed to replace 4-20mA. It did, mostly, over thirty years. Industrial Ethernet was supposed to eliminate serial communication. Serial communication is still everywhere. Better technology wins in industrial automation on a timeline set by depreciation schedules, workforce transitions, and the risk tolerance of people whose primary job is keeping production running. Those timelines are measured in decades and they do not compress because a standards body publishes a roadmap.&lt;/p&gt;
&lt;p&gt;The &amp;quot;yet&amp;quot; in this article&#39;s title has a deadline. The honest answer, based on everything the industry has demonstrated about how protocol transitions actually unfold, is that it is further away than the whitepapers suggest and closer than the Modbus installed base makes it feel.&lt;/p&gt;
&lt;p&gt;Plan accordingly. Build the gateway layer. Invest in OPC UA skills before you need them urgently. Specify OPC UA where the problem justifies it today. And stop expecting the field device layer to look like the SCADA layer anytime soon.&lt;/p&gt;
&lt;p&gt;Modbus will be there when you get back.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/</id>
        <title>How to Parse Binary Data from Serial Devices</title>
        <summary>When your device doesn&#39;t speak Modbus, here&#39;s how you read it</summary>
        <updated>2026-03-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Your device is sending bytes. You don&#39;t know what they mean. The device manual is a 40-page PDF from 2003, and page 12 has a table of numbers with no explanation of what to do with them.&lt;/p&gt;
&lt;p&gt;This is the situation most engineers hit when they connect a legacy serial device for the first time. The serial connection works. The bytes arrive. But nothing tells you what those bytes represent, and there is no standard to fall back on the way there is with Modbus.&lt;/p&gt;
&lt;p&gt;This article gives you a repeatable method for decoding binary output from any serial device. We&#39;ll use an industrial weighing scale as the example. By the end, you&#39;ll know exactly how to approach your own device, regardless of what it sends.&lt;/p&gt;
&lt;h2 id=&quot;the-method&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#the-method&quot;&gt;The Method&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every binary parsing problem follows the same four steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the manual.&lt;/strong&gt; Find the communication protocol section, not the installation guide. You are looking for the frame structure, the byte order, and the data types for each field. If the manual calls it a &amp;quot;data format&amp;quot; or &amp;quot;output format&amp;quot; section, that is the one. Everything else depends on this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identify the frame type.&lt;/strong&gt; Frames from serial devices arrive in one of three structures. Fixed length frames are the simplest — every message is always the same number of bytes. Delimiter terminated frames end with a specific byte or sequence. Length prefixed frames include a byte early in the message that tells you how many bytes follow. Knowing which type your device uses determines how you validate and reassemble frames before parsing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validate before you parse.&lt;/strong&gt; Every frame should pass a basic sanity check before your parsing logic runs. At minimum, verify the frame length and any start or end markers your device includes. If your device provides a checksum, verify that too. A frame that fails validation gets dropped. A corrupted value that passes through and ends up on a dashboard or in a database is far more damaging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Map the bytes.&lt;/strong&gt; Once a frame passes validation, assign every byte a meaning based on the manual. Name, type, offset, endianness, scale. This is where FlowFuse&#39;s Buffer Parser node does its work, visually, without code, with every field visible at a glance.&lt;/p&gt;
&lt;p&gt;The rest of this article walks through all four steps using a concrete example.&lt;/p&gt;
&lt;h2 id=&quot;the-example%3A-industrial-weighing-scale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#the-example%3A-industrial-weighing-scale&quot;&gt;The Example: Industrial Weighing Scale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll use a common industrial weighing scale that outputs data over RS-232. You&#39;ll find this type of device in packaging lines, logistics warehouses, and food processing plants. It has no Modbus support. It sends its own fixed binary frame every time a stable reading is available.&lt;/p&gt;
&lt;p&gt;The manual specifies a fixed-length frame of exactly 10 bytes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;STX, start of frame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1–4&lt;/td&gt;
&lt;td&gt;32-bit float&lt;/td&gt;
&lt;td&gt;Weight value, little-endian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x01&lt;/code&gt; or &lt;code&gt;0x02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unit indicator, 1 = kg, 2 = lb&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Bitfield&lt;/td&gt;
&lt;td&gt;Status flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Reserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Byte&lt;/td&gt;
&lt;td&gt;Checksum, sum of bytes 1–7 truncated to one byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x03&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ETX, end of frame&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Byte 0 is always &lt;code&gt;0x02&lt;/code&gt;. Byte 9 is always &lt;code&gt;0x03&lt;/code&gt;. These are your frame markers. Bytes 1 through 4 carry the weight as a 32-bit IEEE 754 float in little-endian order, meaning the least significant byte comes first. Byte 5 tells you whether the scale is set to kilograms or pounds. Byte 6 is a status bitfield where individual bits carry meaning — bit 0 is stable, bit 1 is overload, bit 2 is zero.&lt;/p&gt;
&lt;p&gt;This is the raw buffer the scale sends for a 23.5 kg stable reading:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Buffer 02 00 00 bb 41 01 03 00 5f 03&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the end of this article, that buffer becomes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-143&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-143&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;23.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;stable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;overload&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;zero&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-143&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;building-the-flow-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#building-the-flow-in-flowfuse&quot;&gt;Building the Flow in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll simulate the device output using an Inject node so you can follow along without hardware. In a real deployment, the Inject node is replaced by a Serial In node receiving bytes directly from the device. The parsing logic, the validation, the Buffer Parser configuration — all of it stays identical. The only difference is where the bytes come from. If you want to set up the actual serial connection, &lt;a href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/&quot;&gt;this article covers that&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The flow is: &lt;strong&gt;Inject node&lt;/strong&gt; connected to a &lt;strong&gt;Function node&lt;/strong&gt; connected to a &lt;strong&gt;Buffer Parser node&lt;/strong&gt; connected to a &lt;strong&gt;Switch node&lt;/strong&gt;, each output of the Switch connected to its own &lt;strong&gt;Change node&lt;/strong&gt;, both Change nodes connected to a &lt;strong&gt;Debug node.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-install-the-buffer-parser-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#step-1%3A-install-the-buffer-parser-node&quot;&gt;Step 1: Install the Buffer Parser Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Buffer Parser node is not included in Node-RED by default. To install it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the hamburger menu (top right)&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Manage palette&lt;/strong&gt; → &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for node-red-contrib-buffer-parser&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, the node will appear in your palette and you can proceed with building the flow. If you&#39;re on FlowFuse, your administrator may have already added it to your shared palette — check before installing.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-simulate-the-device&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#step-2%3A-simulate-the-device&quot;&gt;Step 2: Simulate the Device&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and double-click it&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;msg.payload&lt;/strong&gt; type to &lt;strong&gt;Buffer&lt;/strong&gt; from the dropdown&lt;/li&gt;
&lt;li&gt;Enter: &lt;code&gt;[2,0,0,188,65,1,3,0,1,3]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every time you click the Inject button, the flow receives these 10 bytes exactly as it would from a live serial connection.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-validate-the-frame&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#step-3%3A-validate-the-frame&quot;&gt;Step 3: Validate the Frame&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add a &lt;strong&gt;Function node&lt;/strong&gt; and paste in the following. This is the only JavaScript in the entire flow.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-223&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-223&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; buf &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Check frame length&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Check start and end markers&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x02&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x03&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Validate checksum&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    sum &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-223&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Three checks: frame length, start and end markers, checksum. If any fail, the message is dropped. Only clean, verified frames reach the Buffer Parser.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-parse-the-bytes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#step-4%3A-parse-the-bytes&quot;&gt;Step 4: Parse the Bytes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add a &lt;strong&gt;Buffer Parser node&lt;/strong&gt; and double-click it. Set &lt;strong&gt;Output&lt;/strong&gt; to &lt;strong&gt;key/value&lt;/strong&gt;. Then add one row for each field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weight&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;weight&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;floatle&lt;/code&gt; (32-bit IEEE 754 float, little-endian)&lt;/li&gt;
&lt;li&gt;Offset: &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Length: &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;unit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;uint8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Offset: &lt;code&gt;5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Length: &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Status flag — stable&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;stable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;bool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Offset: &lt;code&gt;6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bit Offset: &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Status flag — overload&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;overload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;bool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Offset: &lt;code&gt;6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bit Offset: &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Status flag — zero&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;zero&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;bool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Offset: &lt;code&gt;6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bit Offset: &lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Buffer Parser node configuration showing weight, unit, and status flag fields mapped to their respective byte offsets&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/buffer-parser.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the Buffer Parser node to extract weight, unit, and status flags from the 10-byte frame&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The float conversion, the byte reading, the individual bit extraction — all handled visually without code. The &lt;code&gt;bool&lt;/code&gt; type with Bit Offset is what makes bitfield parsing possible here. Each status flag is packed into a single byte, and the Buffer Parser pulls them out one bit at a time. If you want a deeper walkthrough of every Buffer Parser field and configuration option, &lt;a href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/&quot;&gt;this article covers it in full&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-map-the-unit-value&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#step-5%3A-map-the-unit-value&quot;&gt;Step 5: Map the Unit Value&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Buffer Parser gives you &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; for the unit byte. A &lt;strong&gt;Switch node&lt;/strong&gt; routes the message based on that value, and a &lt;strong&gt;Change node&lt;/strong&gt; on each route sets the correct label.&lt;/p&gt;
&lt;p&gt;Configure the Switch node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Property: &lt;code&gt;msg.payload.unit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Rule 1: equals &lt;code&gt;1&lt;/code&gt; → output 1&lt;/li&gt;
&lt;li&gt;Rule 2: equals &lt;code&gt;2&lt;/code&gt; → output 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Connect each output to its own Change node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Output 1 Change node: set &lt;code&gt;msg.payload.unit&lt;/code&gt; to the string &lt;code&gt;&amp;quot;kg&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Output 2 Change node: set &lt;code&gt;msg.payload.unit&lt;/code&gt; to the string &lt;code&gt;&amp;quot;lb&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Connect both Change nodes to the Debug node. Click &lt;strong&gt;Deploy&lt;/strong&gt;, then click the Inject button. Your debug panel will show:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-408&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-408&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;weight&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;23.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;stable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;overload&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;zero&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-408&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;div id=&quot;nr-flow-257&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow257 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;5ee755d20d300b60&#92;&quot;,&#92;&quot;e07e9371618f926f&#92;&quot;,&#92;&quot;aedfa06fb7109f18&#92;&quot;,&#92;&quot;045959569e84a098&#92;&quot;,&#92;&quot;947db003dbd32127&#92;&quot;,&#92;&quot;23c25ca58a0784b0&#92;&quot;,&#92;&quot;e541260b3b581eac&#92;&quot;],&#92;&quot;x&#92;&quot;:1294,&#92;&quot;y&#92;&quot;:719,&#92;&quot;w&#92;&quot;:1012,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;5ee755d20d300b60&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[2,0,0,188,65,1,3,0,1,3]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;bin&#92;&quot;,&#92;&quot;x&#92;&quot;:1390,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e07e9371618f926f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e07e9371618f926f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Validate Frame&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const buf = msg.payload;&#92;&#92;n&#92;&#92;n// Check frame length&#92;&#92;nif (buf.length !== 10) {&#92;&#92;n    return null;&#92;&#92;n}&#92;&#92;n&#92;&#92;n// Check start and end markers&#92;&#92;nif (buf[0] !== 0x02 || buf[9] !== 0x03) {&#92;&#92;n    return null;&#92;&#92;n}&#92;&#92;n&#92;&#92;n// Validate checksum&#92;&#92;nlet sum = 0;&#92;&#92;nfor (let i = 1; i &amp;lt;= 7; i++) {&#92;&#92;n    sum += buf[i];&#92;&#92;n}&#92;&#92;nif ((sum &amp;amp; 0xFF) !== buf[8]) {&#92;&#92;n    return null;&#92;&#92;n}&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1560,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aedfa06fb7109f18&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aedfa06fb7109f18&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;buffer-parser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse Frame&#92;&quot;,&#92;&quot;data&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;dataType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;specification&#92;&quot;:&#92;&quot;spec&#92;&quot;,&#92;&quot;specificationType&#92;&quot;:&#92;&quot;ui&#92;&quot;,&#92;&quot;items&#92;&quot;:[{&#92;&quot;type&#92;&quot;:&#92;&quot;floatle&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;weight&#92;&quot;,&#92;&quot;offset&#92;&quot;:1,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:0,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;uint8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;unit&#92;&quot;,&#92;&quot;offset&#92;&quot;:5,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:0,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;stable&#92;&quot;,&#92;&quot;offset&#92;&quot;:6,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:0,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;overload&#92;&quot;,&#92;&quot;offset&#92;&quot;:6,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:1,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;zero&#92;&quot;,&#92;&quot;offset&#92;&quot;:6,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:2,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;}],&#92;&quot;swap1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap3&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap1Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap2Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap3Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;msgProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;msgPropertyType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;resultType&#92;&quot;:&#92;&quot;keyvalue&#92;&quot;,&#92;&quot;resultTypeType&#92;&quot;:&#92;&quot;return&#92;&quot;,&#92;&quot;multipleResult&#92;&quot;:false,&#92;&quot;fanOutMultipleResult&#92;&quot;:false,&#92;&quot;setTopic&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1750,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;045959569e84a098&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;045959569e84a098&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Map Unit&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;msg.payload.unit&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:1920,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;947db003dbd32127&#92;&quot;],[&#92;&quot;23c25ca58a0784b0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;947db003dbd32127&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set kg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.unit&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;kg&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2070,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e541260b3b581eac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;23c25ca58a0784b0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set lb&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.unit&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;lb&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2070,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e541260b3b581eac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e541260b3b581eac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d8bc179d698f39a2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:2210,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f0a3951924692010&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-buffer-parser&#92;&quot;:&#92;&quot;3.2.2&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow257.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-257&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;when-things-get-harder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#when-things-get-harder&quot;&gt;When Things Get Harder&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The weighing scale had a clean, fixed-length frame. Not every device will.&lt;/p&gt;
&lt;h3 id=&quot;frames-arriving-split-across-multiple-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#frames-arriving-split-across-multiple-messages&quot;&gt;Frames Arriving Split Across Multiple Messages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Depending on baud rate and buffer size, a single frame can arrive as two or more separate messages. If you try to parse a partial frame, you get garbage. The fix is a reassembly Function node placed before the validation step, using node context to accumulate bytes until a full frame is available:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-422&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-422&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;buffer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;alloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;buffer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;buffer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-422&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;For delimiter-terminated frames, replace the length check with a search for your end byte. For length-prefixed frames, read the length byte first and use that as your target size.&lt;/p&gt;
&lt;h3 id=&quot;when-buffer-parser-is-not-enough&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#when-buffer-parser-is-not-enough&quot;&gt;When Buffer Parser Is Not Enough&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Buffer Parser handles fixed-structure protocols well. Two situations require a Function node instead.&lt;/p&gt;
&lt;p&gt;The first is conditional structure — where the layout of later bytes depends on the value of an earlier byte. Buffer Parser parses a fixed specification every time. If your frame changes shape based on its own content, you need code.&lt;/p&gt;
&lt;p&gt;The second is complex computed fields. If your device sends a raw ADC value that requires a multi-step calibration formula, Buffer Parser&#39;s scale field won&#39;t cover it. Add a Function node after Buffer Parser to handle only that calculation.&lt;/p&gt;
&lt;p&gt;In both cases: let Buffer Parser do what it can, and add a Function node only for the parts it cannot.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&#39;re on FlowFuse, you don&#39;t need to write that JavaScript yourself. Describe what you need to the &lt;a href=&quot;https://flowfuse.com/docs/user/expert/node-red-embedded-ai/#function-code-generation&quot;&gt;FlowFuse Expert&lt;/a&gt; in plain English and paste the relevant section of your device manual. It will generate the Function node directly on your canvas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompt you can use:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;I have a serial device sending binary data with this frame structure:
- Byte 0: 0x02 (start)
- Byte 1: message type
- Bytes 2–5: 32-bit float (little-endian)
- Byte 6: status bitfield
- Last byte: checksum (sum of bytes)

The frame structure changes based on the message type.

Generate a Node-RED Function node that:
1. Validates the frame (start, length, checksum)
2. Parses fields based on message type
3. Extracts bitfield values into booleans
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Paste your device manual section along with the prompt for best results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;applying-this-to-your-own-device&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#applying-this-to-your-own-device&quot;&gt;Applying This to Your Own Device&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The weighing scale is one device. To show the method transfers, here is how it applies to a completely different device — an industrial barcode scanner.&lt;/p&gt;
&lt;p&gt;The scanner sends a variable-length frame every time it reads a label. The manual specifies a delimiter-terminated structure ending with &lt;code&gt;0x0D&lt;/code&gt; (carriage return). Here is the frame layout:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;STX, start of frame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;uint8&lt;/td&gt;
&lt;td&gt;Scanner ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2–N&lt;/td&gt;
&lt;td&gt;ASCII bytes&lt;/td&gt;
&lt;td&gt;Barcode data, variable length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N+1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x0D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CR, end of frame&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The device and the frame look nothing like the weighing scale. The method is identical.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the manual.&lt;/strong&gt; Frame structure: delimiter terminated, ends with &lt;code&gt;0x0D&lt;/code&gt;. Data types: ASCII bytes for the barcode value, uint8 for the scanner ID.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identify the frame type.&lt;/strong&gt; Delimiter terminated. Your reassembly logic searches for &lt;code&gt;0x0D&lt;/code&gt; instead of checking a fixed length.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validate before you parse.&lt;/strong&gt; Check for the STX start byte at position 0 and the &lt;code&gt;0x0D&lt;/code&gt; end byte at the last position. No checksum on this device, so those two markers are your full validation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Map the bytes.&lt;/strong&gt; In the Buffer Parser, one row for the scanner ID at offset 1 as uint8. The barcode data is ASCII from offset 2 to the end of the frame, which you read as a string type with the appropriate length.&lt;/p&gt;
&lt;p&gt;Four steps. Different device, different frame structure, same process. The Buffer Parser configuration looks different because the bytes are different. The thinking behind it is the same.&lt;/p&gt;
&lt;p&gt;This is what the method gives you. Not a recipe for one specific device, but a way of reading any device manual and turning what you find there into a working flow.&lt;/p&gt;
&lt;p&gt;If you are managing flows across multiple edge devices, FlowFuse deploys the same configuration everywhere through its remote deployment pipeline, with snapshots to roll back if anything changes on the device side.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-parse-binary-data-serial-devices/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus made binary parsing approachable because someone defined the rules in advance. Raw serial devices hand you a PDF instead. That is the real difficulty, not the parsing itself.&lt;/p&gt;
&lt;p&gt;The method in this article works for weighing scales, barcode scanners, RFID readers, CNC machines, and whatever proprietary hardware is sitting on your factory floor with no documentation beyond a table of hex values. Once you have applied it once, you will recognize the pattern in every device you connect after it.&lt;/p&gt;
&lt;p&gt;The factories with the most valuable operational data are often the ones running the oldest hardware. That data is accessible. It just requires knowing how to read it.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/</id>
        <title>Rethinking Edge AI&#39;s Core Orchestration</title>
        <summary>2026 is well underway - where are you going?</summary>
        <updated>2026-03-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Every week, another vendor promises &amp;quot;AI on the edge&amp;quot; with glossy demos and yet another dashboard. With FlowFuse customers though, in real factories, the hard part is not the model; it is getting trustworthy, contextual data from all machines to the right AI, at the right time.The real competitive advantage will not come from who has the flashiest model, but from who owns the most reliable connecting tissue between hardware, IT systems, AI agents, and the cloud. This tissue empowers better model accuracy and creates an operational advantage for our customers.&lt;/p&gt;
&lt;h2 id=&quot;why-ai-deployments-fail-when-you-forget-about-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/#why-ai-deployments-fail-when-you-forget-about-connectivity&quot;&gt;Why AI Deployments Fail When You Forget About Connectivity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturers that have already modernized their SCADA or rolled out cloud data lakes, lake houses, and other lake-based properties, are often surprised by how fragile their &amp;quot;AI initiative&amp;quot; becomes once it touches the factory floor.
It is no secret that data is trapped in proprietary PLCs and vendor‑locked SCADA systems, with IT and OT speaking different languages or protocols, and every site maintaining its own patchwork of scripts, gateways, and one‑off integrations.
So what happens? You end up with predictable problems: fragile, one-off connections, IT changes that take half a year, OT changes that have impact on data semantics but go unnoticed and AI projects that look great on paper but never actually run in the real world at scale.
The fundamental issue lies in the deep divide between Information Technology (IT) and Operational Technology (OT). Shop floor teams are often left in the dark about how their data is leveraged by upstream systems, while IT teams struggle to grasp the operational significance underlying the tags and signals they process. This unbridged gap ensures that every AI initiative remains an expensive, custom-built, and inherently brittle undertaking.&lt;/p&gt;
&lt;h2 id=&quot;the-new-stack%3A-ai%E2%80%91driven-edge-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/#the-new-stack%3A-ai%E2%80%91driven-edge-connectivity&quot;&gt;The new stack: AI‑driven edge connectivity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A different architecture is emerging: a unified, future-proof connectivity layer that sits between machines, plant networks, enterprise systems, and AI services. This layer becomes the common ground where IT and OT share a unified model of metrics from assets, other events, and decisions made, ensuring that neither side operates in a vacuum. And I have to say that I’m proud of stating that FlowFuse is at the forefront of this innovation.
In this new paradigm we’re facing, edge devices run a consistent runtime, such as open-source Node‑RED, so that connectivity, transformation, and control logic look the same on every line, every site, and every device family.
AI is then wired directly into this connective tissue via emerging AI standards like Model Context Protocol (MCP) and other native AI nodes, turning the connectivity fabric into a living &amp;quot;nerve system&amp;quot; where agents can safely read, reason, and act on live operational data.&lt;/p&gt;
&lt;h2 id=&quot;ok-but%E2%80%A6-what-%22future-proof%22-means-at-the-edge%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/#ok-but%E2%80%A6-what-%22future-proof%22-means-at-the-edge%3F&quot;&gt;OK but… what &amp;quot;Future-Proof&amp;quot; means at the edge?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Getting AI, especially large language models (LLMs), to work with the edge isn&#39;t just about sticking them onto your existing middleware. It means that AI is embedded into how connectivity is designed, deployed, and operated: models and agents that turn natural‑language descriptions into flows, blueprints that spin up AI chat agents over plant data, and smart suggestions that propose the next node or transformation in context.
The main thing is, it also means that AI agents can run close to the process, on a gateway or industrial PC, using ONNX models for things like spotting defective parts produced,  and predicting maintenance and downtime, while the cloud handles the rules, oversight, and updates for the whole fleet.
That split (smart procedures happening at the edge, and the cloud just keeping things organized) is precisely what makes the IT and OT worlds finally click. OT gets to be fast and independent, and IT still has the main view and control over the whole shebang.&lt;/p&gt;
&lt;h2 id=&quot;we-can-finally-say-goodbye-to-the-it%2Fot-gap.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/#we-can-finally-say-goodbye-to-the-it%2Fot-gap.&quot;&gt;We can finally say goodbye to the IT/OT gap.&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse was built on a simple belief: industrial teams need one platform that can connect any machine, move data across any protocol, model it in any data platform, and run applications wherever they create the most value.
Both IT and OT get the tools they need, from a wide connectivity suite, to Git integration, and a platform to scale it to hundreds or thousands of different devices.It hooks up to things like PLCs, sensors, and existing Operational Technology (OT) gear using standard protocols like Modbus, OPC UA, and MQTT. This lets you securely stream data to the cloud or your own premises without messing around with complicated firewalls or VPNs. You name it, FlowFuse will connect everything.
At the enterprise level, FlowFuse Cloud provides the central &amp;quot;control tower&amp;quot; to standardize blueprints, ensure version consistency, enforce security policies, and roll out changes across hundreds or thousands of devices with a single action.&lt;/p&gt;
&lt;p&gt;On top of this connectivity fabric, FlowFuse Expert acts as the AI assistant tuned for industrial teams that will make your life easier as you never imagined.
Grounded via MCP in your actual machines, brokers, and databases, it does much more than chat: it generates live Node‑RED flows, data mappings, dashboards, and even queries that are directly deployable into your environment. Because it connects to both OT sources (PLCs, industrial brokers, historians) and IT systems (data lakes, CMDBs, corporate apps), Expert sees, understands and manages both halves of the map. 100% control of both IT and OT. It translates plant-floor requirements into IT-compliant flows and ensures that security and governance policies are automatically applied to edge configurations. It acts as the structural bridge that finally closes the IT/OT gap.
For OT engineers, this means months‑long projects compress into days or minutes; for IT, it means governance and security controls stay intact even as more of the work shifts closer to the plant floor.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;IT/OT Gap Diagram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Rethinking-Edge-AI&#39;s-Core-Orchestration-diagram.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;IT/OT Gap Diagram&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;from-pilots-to-a-scalable-%22ai-nerve-system%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/Rethinking-Edge-AIs-Core-Orchestration/#from-pilots-to-a-scalable-%22ai-nerve-system%22&quot;&gt;From pilots to a scalable &amp;quot;AI nerve system&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s the thing - Most companies will not win by building the most sophisticated individual model, but by institutionalizing a repeatable pattern: connect, contextualize, and act on data at the edge, with AI embedded at every step. If you’ve followed FlowFuse’s history you’ve probably seen how our tagline and our storytelling has been evolving following that logic. “Connect, Collect, Build and Scale with FlowFuse” - This is what this is about.
FlowFuse gives manufacturers that pattern in a form they can actually operate: open‑source at the core with Node‑RED, industrial‑grade features for deployment and observability, and a layer of proprietary Artificial Intelligence that actually understands the realities of plant networks, not just cloud APIs.
The result is a new kind of infrastructure: a persistent &amp;quot;AI nerve system&amp;quot; that spans hardware, IT, AI, and cloud, so that when the next model, vendor, or use case arrives, your connectivity is already in place, deployed and ready to scale. This structural bridge ensures that the historical friction between IT and OT becomes a foundation for collaboration.
If the last decade was about moving workloads to the cloud, the next decade in manufacturing will be about bringing intelligence to the edge. And how this must be done? Safely, consistently, and fast enough to matter.
The companies that treat AI‑driven edge connectivity as a strategic foundation, not a side project, will be the ones that turn experiments into durable competitive advantage.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/</id>
        <title>5 Places Smart Factories Are Already Using AI</title>
        <summary>Where AI Is Actually Working on the Factory Floor</summary>
        <updated>2026-03-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The factory floor wasn&#39;t exactly an early adopter of artificial intelligence.&lt;/p&gt;
&lt;p&gt;It&#39;s a world built around physical processes: tolerances, throughput, shift schedules. The automation that arrived decades ago was powerful but rigid. Machines that did exactly what you programmed them to do, nothing more.&lt;/p&gt;
&lt;p&gt;That&#39;s changed.&lt;/p&gt;
&lt;p&gt;AI is now embedded in manufacturing operations in ways that are easy to miss. Not in the headline-grabbing robots, but in the systems quietly running underneath: predicting failures, catching defects, optimizing energy loads, and compressing deployment timelines.&lt;/p&gt;
&lt;p&gt;The question isn&#39;t whether AI has reached the factory floor. It has. The question is where it&#39;s actually doing useful work.&lt;/p&gt;
&lt;p&gt;Here are five answers.&lt;/p&gt;
&lt;h2 id=&quot;predictive-maintenance-on-cnc-machines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#predictive-maintenance-on-cnc-machines&quot;&gt;Predictive Maintenance on CNC Machines&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturers lose $50 billion a year to unplanned downtime. Here&#39;s what that actually looks like: a CNC machine goes down at 2am, the part isn&#39;t in stock, the order misses its window, and the schedule takes three days to recover.&lt;/p&gt;
&lt;p&gt;The problem was never detection. Factories have had sensors for decades. It was interpretation. A temperature spike means nothing without knowing what&#39;s normal for that machine, on that material, at that feed rate. Threshold-based alarms can&#39;t know that. A model trained on months of operational data from that specific machine can.&lt;/p&gt;
&lt;p&gt;Predictive maintenance learns the baseline and watches for drift. Bearing wear shows up as a frequency shift in vibration data. Spindle imbalance leaves a signature in motor current. None of these are visible on the floor, but all of them are readable in the data, 24 to 72 hours before failure.&lt;/p&gt;
&lt;p&gt;Harley-Davidson has been running vibration-based predictive maintenance on plant equipment for longer than most manufacturers realize. But you don&#39;t need that scale. We built an &lt;a href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/&quot;&gt;AI vibration anomaly detector for industrial motors&lt;/a&gt; using an autoencoder trained on healthy vibration data, running inference directly in Node-RED. The model learns what normal looks like. When that changes, you get a warning with time to act.&lt;/p&gt;
&lt;p&gt;That&#39;s the shift. Not better alarms, but a system that knows the difference between a machine running hard and a machine running out of time.&lt;/p&gt;
&lt;h2 id=&quot;visual-quality-inspection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#visual-quality-inspection&quot;&gt;Visual Quality Inspection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manual inspection has a hard ceiling. Put someone at a line running 200 units a minute for four hours and their defect detection rate drops. That&#39;s not a training problem. It&#39;s physiology.&lt;/p&gt;
&lt;p&gt;Computer vision doesn&#39;t have that ceiling. A camera at the inspection station sees every unit, not a sample, at full line speed, catching surface defects, dimensional drift, solder bridges, and weld inconsistencies. In semiconductor fabrication, where a particle smaller than a human hair destroys yield, vision-based inspection isn&#39;t an upgrade. It&#39;s the only option that makes sense at volume.&lt;/p&gt;
&lt;p&gt;BMW&#39;s &lt;a href=&quot;https://www.press.bmwgroup.com/global/article/detail/T0449729EN/artificial-intelligence-as-a-quality-booster?language=en&quot;&gt;AIQX platform&lt;/a&gt; runs camera and sensor-based AI quality checks across every plant globally. At Spartanburg, it monitors roughly &lt;a href=&quot;https://www.automotivemanufacturingsolutions.com/smart-factory/quality-visions-ai-inspection-systems-that-learns-from-the-line/2623126&quot;&gt;half a million weld studs daily&lt;/a&gt;. At Regensburg, the &lt;a href=&quot;https://www.press.bmwgroup.com/global/article/detail/T0449729EN/artificial-intelligence-as-a-quality-booster?language=en&quot;&gt;GenAI4Q system&lt;/a&gt; generates a custom inspection checklist for each of 1,400 vehicles built daily, adapting to every model variant in real time.&lt;/p&gt;
&lt;p&gt;There&#39;s a compounding effect worth noting: every defect caught becomes labeled training data. The model improves continuously. The longer it runs, the harder it is to beat.&lt;/p&gt;
&lt;p&gt;Human inspectors still matter for root cause and edge cases. But the first pass, the one that runs on every unit at line speed, is not a job for human eyes anymore.&lt;/p&gt;
&lt;h2 id=&quot;shorter-path-from-pilot-to-production&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#shorter-path-from-pilot-to-production&quot;&gt;Shorter Path from Pilot to Production&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturers consistently underestimate integration time. The technology decisions get made, the use case is clear, and then the project stalls for months. The pilot ran on clean exported data. Production means live data from PLCs running proprietary protocols, historians not designed for real-time access, and network segments that exist for good reasons. Most IIoT initiatives don&#39;t fail at the algorithm layer. They fail at the plumbing.&lt;/p&gt;
&lt;p&gt;That gap is expensive. A deployment that takes six months to reach production has a very different ROI profile than one that takes six weeks. And it&#39;s precisely here that AI is changing the economics of development. Engineers are generating integration flows from plain language descriptions, tracing protocol mismatches that would have previously burned days, and producing documentation as they build rather than long after. The unglamorous middle work moves faster.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;FlowFuse Expert&lt;/a&gt; is built for exactly this. AI assistance embedded directly in the Node-RED editor: inline code completions as you write, next-node predictions as you build, and a chat interface that understands your actual flows and live debug output. Describe the logic you need and it writes the function node. Something behaving unexpectedly? Load your flow and debug logs as context and work through it together. Fewer hours lost to problems that have already been solved a hundred times before.&lt;/p&gt;
&lt;h2 id=&quot;energy-and-hvac-optimization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#energy-and-hvac-optimization&quot;&gt;Energy and HVAC Optimization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most smart factory conversations never get to the building itself. That&#39;s a mistake.&lt;/p&gt;
&lt;p&gt;HVAC is one of the largest energy costs in a manufacturing facility and one of the least optimized. A factory&#39;s thermal load shifts constantly: which lines are running, what materials are being processed, outdoor temperature, occupancy. Rule-based systems deal with that complexity by setting conservative margins everywhere and leaving them there. It works, but you pay for it on every energy bill.&lt;/p&gt;
&lt;p&gt;AI learns the actual behavior of the facility and stops defending against conditions that aren&#39;t happening. Yokogawa deployed reinforcement learning for HVAC in its semiconductor plant in Japan. In that facility, cleanroom HVAC accounted for roughly &lt;a href=&quot;https://www.isa.org/intech-home/2022/october-2022/features/case-study-ai-based-autonomous-control&quot;&gt;30 percent of total energy consumption&lt;/a&gt; — a figure consistent with, though on the lower end of, what&#39;s reported across the semiconductor industry. The result was a &lt;a href=&quot;https://my.avnet.com/silica/resources/article/ai-takes-on-growing-role-in-hvac-system-efficiencies/&quot;&gt;3.6 percent reduction&lt;/a&gt; in total consumption. Modest on paper, significant at scale, and it improves as the model keeps learning.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deepmind.google/discover/blog/deepmind-ai-reduces-google-data-centre-cooling-bill-by-40/&quot;&gt;DeepMind&#39;s data center work&lt;/a&gt; gets more attention, but that&#39;s a controlled, single-purpose environment. A factory is harder. Yokogawa is the more relevant proof of concept.&lt;/p&gt;
&lt;h2 id=&quot;worker-safety-and-ergonomics-monitoring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#worker-safety-and-ergonomics-monitoring&quot;&gt;Worker Safety and Ergonomics Monitoring&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Musculoskeletal disorders are the most common workplace injury in manufacturing. A bad lift, an awkward reach, a sustained bent posture on a repetitive task: the injury doesn&#39;t happen dramatically. It accumulates over weeks, then shows up as a compensation claim and a gap on the line.&lt;/p&gt;
&lt;p&gt;Traditional ergonomics assessment catches this late. A consultant observes a workstation, writes a report, and by the time recommendations are implemented, workers have been loading their joints wrong for months.&lt;/p&gt;
&lt;p&gt;Pose-estimation AI runs overhead cameras continuously and scores every movement in real time against established ergonomic risk frameworks, flagging a bend angle that will cause a back injury long before it materializes. In one &lt;a href=&quot;https://rsisinternational.org/journals/ijrsi/articles/ai-powered-ergonomics-enhancing-workplace-safety-through-posture-detection/&quot;&gt;manufacturing pilot study&lt;/a&gt;, researchers reported roughly a 25 percent reduction in workplace injuries, with posture compliance improving once workers received real-time feedback. Results will vary by facility, workstation type, and baseline injury rates.&lt;/p&gt;
&lt;p&gt;The privacy question deserves a direct answer: these systems track skeletal keypoints, not faces or identities. What gets logged is joint angle data, not footage of individuals.&lt;/p&gt;
&lt;p&gt;What makes this different from a safety poster is that it doesn&#39;t rely on the worker remembering. The system watches every repetition, on every shift.&lt;/p&gt;
&lt;h2 id=&quot;where-to-start&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/ai-usecases-in-factory/#where-to-start&quot;&gt;Where to Start&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The five use cases covered here aren&#39;t experiments. They&#39;re running in production facilities today, on real lines, delivering measurable results. The gap between manufacturers who&#39;ve deployed AI and those still evaluating it is growing, and it compounds.&lt;/p&gt;
&lt;p&gt;But starting doesn&#39;t require a complete digital transformation. Pick one problem that&#39;s costing you money right now: unplanned downtime on a critical machine, a defect rate you can&#39;t get below, an energy bill that doesn&#39;t reflect how efficiently you actually run. That&#39;s your first use case.&lt;/p&gt;
&lt;p&gt;The common thread across all five use cases is the same bottleneck: getting operational data to a model reliably and acting on what it returns. That&#39;s the integration problem most deployments stall on. FlowFuse is built around solving exactly that. You connect to your PLCs, deploy your AI model, and trigger actions all within the same flow, which is why it&#39;s where most manufacturers start and where they keep building.&lt;/p&gt;
&lt;p&gt;The manufacturers seeing results didn&#39;t wait for the perfect conditions. They started with one line, proved the value, and expanded. That&#39;s still the fastest route from where you are to where you want to be.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/</id>
        <title>FlowFuse Enterprise: More Power, More Confidence</title>
        <summary>Introducing Certified Nodes and AI Insights</summary>
        <updated>2026-03-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Manufacturing teams using FlowFuse are running industrial applications at scale — across plants, teams, and environments. As that scale grows, so do the expectations: faster deployments, tighter security, smarter tooling.&lt;/p&gt;
&lt;p&gt;Today we&#39;re announcing updates to our Enterprise tier that reflect where our customers are headed and the kind of platform they need to get there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse Enterprise now includes Certified Nodes and AI Insights.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-new-in-enterprise&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#what&#39;s-new-in-enterprise&quot;&gt;What&#39;s new in Enterprise&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;certified-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#certified-nodes&quot;&gt;Certified Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most consistent questions we hear from IT and security teams evaluating FlowFuse is: &amp;quot;Is FlowFuse secure and compliant enough for production?&amp;quot;&lt;/p&gt;
&lt;p&gt;Certified Nodes are our answer. Every node in the catalogue has been security-scanned, battle-tested, and comes with a clear support owner, along with enterprise level response times. That means your team gets the flexibility of the Node-RED ecosystem with the accountability that enterprise production environments demand.&lt;/p&gt;
&lt;p&gt;This isn&#39;t just a compliance checkbox. It&#39;s the foundation for &lt;strong&gt;trusting your infrastructure&lt;/strong&gt; with the dependencies — and for IT and Operations to standardize on FlowFuse with confidence across sites.&lt;/p&gt;
&lt;h3 id=&quot;ai-insights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#ai-insights&quot;&gt;AI Insights&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Building and iterating on flows takes time — time your team doesn&#39;t always have. AI Insights brings AI-assisted solution building directly into FlowFuse, reducing the effort required to go from idea to production.&lt;/p&gt;
&lt;p&gt;Whether you&#39;re onboarding a new site, adapting an existing flow, or troubleshooting a process, AI Insights helps your team do more with less — and get to value faster.&lt;/p&gt;
&lt;p&gt;Our goal is simple: &lt;strong&gt;the first week of value should come faster than ever before.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;built-around-three-things-that-matter-at-scale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#built-around-three-things-that-matter-at-scale&quot;&gt;Built around three things that matter at scale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These additions aren&#39;t standalone features — they reflect a deliberate focus on the three capabilities manufacturing enterprises need as they move from pilot to production to fleet.&lt;/p&gt;
&lt;h3 id=&quot;operational-scaling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#operational-scaling&quot;&gt;Operational Scaling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deploy and manage Node-RED reliably across sites, teams, and environments — without the configuration drift and version inconsistency that comes with growth.&lt;/p&gt;
&lt;h3 id=&quot;system-agility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#system-agility&quot;&gt;System Agility&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Build, iterate, and adapt faster with AI-assisted tooling. Certified Nodes and AI Insights together mean your team spends less time on asset modeling and more time on outcomes.&lt;/p&gt;
&lt;h3 id=&quot;event-driven-data-bridge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#event-driven-data-bridge&quot;&gt;Event-Driven Data Bridge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Connect your systems with operational responsiveness — not just bulk data collection. FlowFuse is built for the workflow-centric, event-driven logic that manufacturing operations actually run on.&lt;/p&gt;
&lt;h2 id=&quot;what-this-means-for-your-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/enterprise-packaging-updates/#what-this-means-for-your-team&quot;&gt;What this means for your team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse has always been built on Node-RED — but Enterprise customers need more than a great open-source foundation. They need a platform they can stake production operations on.&lt;/p&gt;
&lt;p&gt;Certified Nodes and AI Insights are the next step in making FlowFuse that platform: more accountable, more capable, and faster to value than ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get started at &lt;a href=&quot;https://flowfuse.com/pricing&quot;&gt;flowfuse.com/pricing&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/</id>
        <title>How to Monitor Industrial Network Health Using SNMP</title>
        <summary>Build production-grade SNMP monitoring pipelines with FlowFuse</summary>
        <updated>2026-03-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Industrial networks fail quietly. A saturated uplink, a flapping interface, or a device nearing its resource ceiling degrades silently until a line goes down or a control loop breaks.&lt;/p&gt;
&lt;p&gt;SNMP exists precisely to prevent that. Decades proven, it remains the most reliable protocol for extracting health telemetry from switches, routers, PLCs, and RTUs. No agents, no overhead, runs on everything.&lt;/p&gt;
&lt;p&gt;The gap has always been implementation. Most teams either over-engineer it with heavyweight NMS platforms or under-engineer it with brittle scripts. Neither is acceptable when network visibility is an uptime and safety concern.&lt;/p&gt;
&lt;p&gt;This guide walks through building a production-grade SNMP monitoring pipeline with FlowFuse, polling device metrics, discovering interfaces, and feeding telemetry into a FlowFuse Dashboard where your team can act on it.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before getting started, make sure you have the following in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse:&lt;/strong&gt; A running FlowFuse instance on your edge device. If you do not have an account yet, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; to get started and follow this &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;guide to get Node-RED running&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An SNMP-enabled device:&lt;/strong&gt; Any managed switch, router, PLC, or RTU with SNMP enabled and UDP port 161 accessible from your FlowFuse instance. If you do not have a real device available, you can run a local SNMP agent for testing — see &lt;a href=&quot;http://www.net-snmp.org/download.html/&quot;&gt;net-snmp.org&lt;/a&gt; for installation instructions for your platform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UDP port 161 access:&lt;/strong&gt; Confirm your community string and ensure firewall rules permit SNMP polling from your FlowFuse host to the target device.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;understanding-snmp&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#understanding-snmp&quot;&gt;Understanding SNMP&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol&quot;&gt;SNMP&lt;/a&gt; operates on a simple manager-agent model. The &lt;strong&gt;manager&lt;/strong&gt; (your FlowFuse instance) sends requests to the &lt;strong&gt;agent&lt;/strong&gt; (a network device or server running an SNMP daemon) and the agent responds with the requested data. All communication happens over UDP port 161.&lt;/p&gt;
&lt;p&gt;Data on the agent is organized in a &lt;strong&gt;Management Information Base (MIB)&lt;/strong&gt; — a hierarchical tree of objects, each identified by an &lt;strong&gt;Object Identifier (OID)&lt;/strong&gt;. Every piece of information you can query from a device, its uptime, interface status, traffic counters, CPU load, has a unique OID.&lt;/p&gt;
&lt;p&gt;There are three operations you will use in this guide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GET:&lt;/strong&gt; Fetch the value of a specific OID from a device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WALK:&lt;/strong&gt; Traverse an entire OID subtree and return all values beneath it. Useful for querying all interfaces at once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SUBTREE:&lt;/strong&gt; Fetch a specific OID subtree and everything beneath it. More targeted than a full walk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SNMP also has versions. &lt;strong&gt;SNMPv1&lt;/strong&gt; and &lt;strong&gt;v2c&lt;/strong&gt; use a plain-text community string as authentication. &lt;strong&gt;SNMPv3&lt;/strong&gt; adds user-based authentication and encryption. For production industrial environments, v3 is the right choice. For this guide, we use v2c to keep the focus on the implementation.&lt;/p&gt;
&lt;h2 id=&quot;installing-snmp-package-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#installing-snmp-package-in-flowfuse&quot;&gt;Installing SNMP Package in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;node-red-node-snmp&lt;/code&gt; package provides a set of nodes for communicating with SNMP-enabled devices directly from your flows. Before building the monitoring pipeline, install it into your FlowFuse instance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your FlowFuse instance and navigate to the Node-RED editor.&lt;/li&gt;
&lt;li&gt;Click the hamburger menu in the top-right corner and select &lt;strong&gt;Manage Palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-node-snmp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; and wait for the installation to complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you will see the following nodes available in your palette under the network category:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;snmp&lt;/strong&gt; — fetch one or more specific OIDs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;snmp walker&lt;/strong&gt; — walk from a given OID to the end of the MIB tree&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;snmp subtree&lt;/strong&gt; — fetch a specific OID subtree and everything beneath it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;snmp table&lt;/strong&gt; — fetch structured SNMP table data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;snmp set&lt;/strong&gt; — write values back to a device&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;SNMP nodes available in the Node-RED palette after installing node-red-node-snmp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snmp-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;SNMP nodes available in the Node-RED palette after installing node-red-node-snmp&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For this guide we will be working with &lt;strong&gt;snmp&lt;/strong&gt;, &lt;strong&gt;snmp walker&lt;/strong&gt;, and &lt;strong&gt;snmp subtree&lt;/strong&gt;. These three cover the core read operations needed for network health monitoring.&lt;/p&gt;
&lt;h2 id=&quot;polling-device-metrics-with-snmp-get&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#polling-device-metrics-with-snmp-get&quot;&gt;Polling Device Metrics with SNMP GET&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The snmp node sends a GET request to the agent and returns the values of the OIDs you specify. You can pass a single OID or a comma-separated list — the node fetches all of them in one request and returns the results as an array. This is the right operation when you know exactly what you want to fetch — system uptime, device name, description.&lt;/p&gt;
&lt;p&gt;We will poll three key system OIDs in a single GET request every five seconds. All three sit under the &lt;code&gt;system&lt;/code&gt; group (&lt;code&gt;1.3.6.1.2.1.1&lt;/code&gt;), which is part of &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1213.html&quot;&gt;MIB-II&lt;/a&gt; — the standard MIB supported by virtually every SNMP-enabled device. Standard OIDs are consistent across vendors, so the same OID returns &lt;code&gt;sysUpTime&lt;/code&gt; whether you are querying a Cisco switch, a Siemens PLC, or a Linux server. Vendor-specific metrics live under &lt;code&gt;1.3.6.1.4.1&lt;/code&gt; and vary by device — you will need the vendor&#39;s MIB file for those. For browsing standard OIDs, see the &lt;a href=&quot;https://www.alvestrand.no/objectid/1.3.6.1.2.1.1.html&quot;&gt;OID reference for the system group&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.1.3.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sysUpTime&lt;/td&gt;
&lt;td&gt;How long the device has been running, in timeticks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.1.5.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sysName&lt;/td&gt;
&lt;td&gt;The configured hostname of the device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.1.1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sysDescr&lt;/td&gt;
&lt;td&gt;A full description of the hardware and OS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas and double click it. Set the repeat interval to &lt;strong&gt;every 5 seconds&lt;/strong&gt; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;snmp&lt;/strong&gt; node onto the canvas and double click it to configure:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;IP address of your target device, e.g. &lt;code&gt;192.168.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v2c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OIDs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.1.3.0,1.3.6.1.2.1.1.5.0,1.3.6.1.2.1.1.1.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: OIDs in the list must be comma-separated with no spaces between them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas, connect it to the snmp node output, and click &lt;strong&gt;Deploy&lt;/strong&gt; to verify the raw response first.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You will notice the response is not immediately human-readable. OctetString values such as &lt;code&gt;sysName&lt;/code&gt; and &lt;code&gt;sysDescr&lt;/code&gt; come back as byte arrays, and &lt;code&gt;sysUpTime&lt;/code&gt; arrives as a raw TimeTicks integer:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-273&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-273&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.3.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;67&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;317537&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;tstr&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TimeTicks&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.5.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;116&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;115&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;116&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;tstr&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OctetString&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;114&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;119&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;105&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;tstr&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OctetString&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-273&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We need a function node to convert byte arrays to strings and TimeTicks to a readable uptime format.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas and insert it between the snmp node and the debug node.&lt;/li&gt;
&lt;li&gt;Double click it and add the following code:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-289&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-289&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tstr &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OctetString&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;utf8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tstr &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TimeTicks&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalSeconds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; days &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalSeconds &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;86400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hours &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalSeconds &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;86400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; minutes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalSeconds &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seconds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; totalSeconds &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;days&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;d &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;hours&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;h &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;minutes&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;m &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;seconds&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;oid&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tstr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parsed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-289&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you need different parsing logic for additional OID types or want to transform the output differently, you do not have to write it from scratch. FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/user/expert/node-red-embedded-ai/#function-code-generation&quot;&gt;AI-powered function generation&lt;/a&gt; lets you describe what you need in plain English and generates the function node code for you directly inside the editor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The debug panel will now show clean, readable output:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-305&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-305&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.3.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TimeTicks&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0d 0h 52m 55s&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.5.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OctetString&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;test-device&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;oid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.1.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OctetString&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Linux core-switch-01 5.15.0 #1 SMP x86_64&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-305&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;With system metrics polling cleanly, the next section covers using the snmp walker node to discover and monitor all network interfaces on the device.&lt;/p&gt;
&lt;h2 id=&quot;discovering-interfaces-with-snmp-walker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#discovering-interfaces-with-snmp-walker&quot;&gt;Discovering Interfaces with SNMP Walker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The snmp walker node traverses the MIB tree starting from a given OID and returns every object beneath it. Unlike GET where you specify exact OIDs, walker is useful when you do not know the full OID path in advance — for example, discovering all network interfaces on a device without knowing how many exist or what their index numbers are.&lt;/p&gt;
&lt;p&gt;Network interfaces on any SNMP device live under the &lt;code&gt;ifTable&lt;/code&gt; (&lt;code&gt;1.3.6.1.2.1.2.2&lt;/code&gt;). Walking this subtree returns every interface along with its name, operational status, speed, and traffic counters — one entry per interface regardless of how many the device has.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ifIndex&lt;/td&gt;
&lt;td&gt;Unique index number for each interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ifDescr&lt;/td&gt;
&lt;td&gt;Interface name, e.g. &lt;code&gt;eth0&lt;/code&gt;, &lt;code&gt;GigabitEthernet0/1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ifOperStatus&lt;/td&gt;
&lt;td&gt;Operational status — &lt;code&gt;1&lt;/code&gt; = up, &lt;code&gt;2&lt;/code&gt; = down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ifInOctets&lt;/td&gt;
&lt;td&gt;Total inbound bytes on the interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ifOutOctets&lt;/td&gt;
&lt;td&gt;Total outbound bytes on the interface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Walking from &lt;code&gt;1.3.6.1.2.1.2.2&lt;/code&gt; returns all of the above for every interface in one request. For the full ifTable OID reference see &lt;a href=&quot;https://www.alvestrand.no/objectid/1.3.6.1.2.1.2.2.html&quot;&gt;alvestrand.no/objectid/1.3.6.1.2.1.2.2&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The walker node requires a device with a populated interface table. If you are using a lightweight test agent, increase the timeout in the walker node configuration to at least 30 seconds. On resource-constrained devices that cannot handle bulk requests, use the snmp subtree node instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas and double click it. Set the repeat interval to &lt;strong&gt;every 10 seconds&lt;/strong&gt; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;snmp walker&lt;/strong&gt; node onto the canvas and double click it to configure:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;IP address of your target device, e.g. &lt;code&gt;192.168.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v2c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeout&lt;/td&gt;
&lt;td&gt;&lt;code&gt;30&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas and insert it between the walker node and a debug node. Double click it and add the following code to parse the response into a readable structure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-476&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-476&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; interfaces &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ifIndex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;parts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; subOid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;interfaces&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ifIndex&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; interfaces&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ifIndex&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ifIndex &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; oidMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.1&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ifIndex&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ifDescr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.8&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ifOperStatus&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.10&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ifInOctets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.16&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ifOutOctets&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;oidMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;subOid&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subOid &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;utf8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subOid &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.3.6.1.2.1.2.2.1.8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;up&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;down&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        interfaces&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ifIndex&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;oidMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;subOid&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;interfaces&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ifDescr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-476&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas and connect it to the function node output.&lt;/li&gt;
&lt;li&gt;Connect the inject node output to the walker node input, and the walker node output to the function node input.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The debug panel will show a clean array of interface objects like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-502&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-502&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifDescr&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifOperStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;up&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifInOctets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20526&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifOutOctets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20526&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifDescr&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;enp0s1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifOperStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;up&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifInOctets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;48159944&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;ifOutOctets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4263495&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-502&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Each entry represents one interface with its current operational status and traffic counters. In the next section we will use the snmp subtree node to fetch interface data more precisely by targeting a specific OID subtree.&lt;/p&gt;
&lt;h2 id=&quot;fetching-interface-data-with-snmp-subtree&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#fetching-interface-data-with-snmp-subtree&quot;&gt;Fetching Interface Data with SNMP Subtree&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The snmp subtree node is similar to walker but more targeted. Where walker reads from a given OID to the end of the entire MIB tree, subtree fetches everything beneath a specific OID and stops there. This makes it more predictable and efficient when you know the exact branch you want.&lt;/p&gt;
&lt;p&gt;For network health monitoring, a practical use of subtree is pulling all operational status values for every interface in one shot by targeting &lt;code&gt;ifOperStatus&lt;/code&gt; directly at &lt;code&gt;1.3.6.1.2.1.2.2.1.8&lt;/code&gt;. This gives you a clean up/down status for every interface on the device without pulling traffic counters or other data you do not need at that moment.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas and double click it. Set the repeat interval to &lt;strong&gt;every 10 seconds&lt;/strong&gt; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;snmp subtree&lt;/strong&gt; node onto the canvas and double click it to configure:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;IP address of your target device, e.g. &lt;code&gt;192.168.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v2c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.3.6.1.2.1.2.2.1.8&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas and insert it between the subtree node and a debug node. Double click it and add the following code to parse the interface status values:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-585&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-585&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; statuses &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ifIndex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;parts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;ifIndex&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ifIndex&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;ifOperStatus&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;up&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;down&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; statuses&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-585&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you need different parsing logic for additional OID types or want to transform the output differently, you do not have to write it from scratch. FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/user/expert/node-red-embedded-ai/#function-code-generation&quot;&gt;AI-powered function generation&lt;/a&gt; lets you describe what you need in plain English and generates the function node code for you directly inside the editor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Connect the inject node to the subtree node, the subtree node to the function node, and the function node to a debug node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The debug panel will show a concise status array for every interface:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-611&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-611&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ifIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ifOperStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;up&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ifIndex&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ifOperStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;down&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-611&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This is the most efficient way to run a continuous interface health check, one subtree poll every 10 seconds tells you the operational state of every interface on the device without fetching data you do not need.&lt;/p&gt;
&lt;p&gt;With all three polling operations in place, the next step is wiring this data into a &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; so the information is visible at a glance.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-monitor-industrial-network-usign-snmp/#wrapping-up&quot;&gt;Wrapping Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial networks don&#39;t announce their problems. They accumulate them silently until a line goes down, a control loop breaks, or production stops.&lt;/p&gt;
&lt;p&gt;The pipeline you&#39;ve built here changes that. GET, Walker, and Subtree give you precise, continuous visibility into every device on your network. FlowFuse delivers it without the infrastructure overhead of a full NMS platform or the maintenance burden of hand-rolled scripts.&lt;/p&gt;
&lt;p&gt;Wire the telemetry into a FlowFuse Dashboard. Set threshold-based alerts. Extend your OID coverage to vendor-specific metrics as your requirements grow. The foundation is in place. Everything else is iteration.&lt;/p&gt;
&lt;p&gt;Unmonitored networks are a liability. Now yours isn&#39;t.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/</id>
        <title>Edge vs Cloud AI in Manufacturing: Where Each Actually Belongs</title>
        <summary>Should we run our AI at the edge or in the cloud?</summary>
        <updated>2026-03-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Most industrial AI deployments are built around the wrong question. &amp;quot;Edge or cloud?&amp;quot; treats a deployment decision as a binary choice, when the real question is simpler and more useful: what does this specific workload actually require?&lt;/p&gt;
&lt;p&gt;Edge AI offers real-time inference with no network dependency. Cloud AI offers the depth of compute and data that builds models worth deploying in the first place. Both are genuinely necessary. Neither is universally correct. And the architecture that works is almost always a hierarchy of both, not a choice between them.&lt;/p&gt;
&lt;p&gt;This piece looks at where each layer performs, where each fails, and how to place workloads correctly across the hierarchy. The goal is not a verdict. It is a framework for making the decision well, every time.&lt;/p&gt;
&lt;h2 id=&quot;what-edge-ai-and-cloud-ai-actually-mean-on-the-plant-floor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#what-edge-ai-and-cloud-ai-actually-mean-on-the-plant-floor&quot;&gt;What Edge AI and Cloud AI Actually Mean on the Plant Floor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Edge AI processes data where it is generated. The model runs locally on a gateway or industrial PC, directly on the factory floor. Data from sensors, cameras, and machines is analyzed on the spot, and the result is immediate.&lt;/p&gt;
&lt;p&gt;Cloud AI processes data in a remote data center. Information travels over a network to where the compute lives. The infrastructure scales to meet demand, and the same models can serve every site in an operation.&lt;/p&gt;
&lt;p&gt;Both are real approaches to industrial AI, built for different problems and different scales.&lt;/p&gt;
&lt;h2 id=&quot;where-edge-ai-works-best&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#where-edge-ai-works-best&quot;&gt;Where Edge AI Works Best&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Think about what happens in the seconds after a sensor detects something abnormal on a running line. There is no time to package that data, send it to a remote server, wait for a response, and act. The machine has already moved on.&lt;/p&gt;
&lt;p&gt;This is the environment edge AI was built for. Manufacturing lines running at speed, assets in remote locations, facilities where network connectivity is inconsistent or restricted. In these situations, the model needs to live close to the source, processing data as it arrives and producing a result before the next event occurs.&lt;/p&gt;
&lt;p&gt;Quality inspection is one of the clearest examples. A vision system identifying surface defects, dimensional errors, or assembly faults on a fast-moving line has a window measured in milliseconds. The same logic applies to condition monitoring on rotating equipment, anomaly detection on process instrumentation, and real-time control adjustments based on live sensor feeds.&lt;/p&gt;
&lt;p&gt;Edge AI also matters where data cannot easily leave the facility. Regulatory requirements, network constraints, or simple operational practicality all create situations where keeping data local is not optional. Running the model at the edge removes the dependency entirely.&lt;/p&gt;
&lt;p&gt;The use cases are varied but the underlying condition is consistent. When speed, proximity, or data locality is non-negotiable, the architecture decision is straightforward.&lt;/p&gt;
&lt;h2 id=&quot;where-cloud-ai-works-best&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#where-cloud-ai-works-best&quot;&gt;Where Cloud AI Works Best&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Edge AI handles the moment. What it cannot handle is everything that happens before that moment becomes possible.&lt;/p&gt;
&lt;p&gt;A single facility sees a fraction of the picture. One site running one set of machines accumulates useful data. But an organization running fifty sites, each generating operational data around the clock, is sitting on something far more valuable. The patterns that predict failure, the process conditions that drive quality, the anomalies that precede downtime. These only become visible when data is brought together at scale.&lt;/p&gt;
&lt;p&gt;That is the problem cloud AI was built to solve. Not speed, but depth. Not real-time response, but the kind of learning that takes weeks of data, hundreds of assets, and serious compute to produce. A predictive model that has seen ten thousand failure events across a global fleet will always outperform one trained on a single site. The cloud is where that model gets built.&lt;/p&gt;
&lt;p&gt;It is also where industrial organizations manage AI at scale. Retraining models as conditions change, pushing updates across distributed deployments, monitoring performance across every site from a single place. Doing that at the edge, independently, across dozens of locations, is not a realistic proposition.&lt;/p&gt;
&lt;p&gt;The workloads that belong in the cloud share a common characteristic. They are not time-critical, but they are data-hungry and compute-intensive. And the value they produce, better models, broader visibility, smarter operations, flows back down to the plant floor where it matters.&lt;/p&gt;
&lt;h2 id=&quot;the-trade-offs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#the-trade-offs&quot;&gt;The Trade-offs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every architecture decision in industrial AI comes down to the same five factors. Get them right and the deployment works. Get them wrong and the problems compound quietly until they become expensive.&lt;/p&gt;
&lt;p&gt;Latency determines whether cloud is even an option for a given workload. Bandwidth determines what it costs to run it. Data ownership determines what is permissible. Model complexity determines what is technically feasible. And operational overhead determines what the true long-term cost looks like, not just the build cost.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Edge&lt;/th&gt;
&lt;th&gt;Cloud&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Real-time, no network dependency&lt;/td&gt;
&lt;td&gt;Adds network round-trip, not suitable for time-critical decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth&lt;/td&gt;
&lt;td&gt;Data stays local, minimal transfer costs&lt;/td&gt;
&lt;td&gt;High volumes must travel, costs and infrastructure scale with data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Ownership&lt;/td&gt;
&lt;td&gt;Stays on site, no external exposure&lt;/td&gt;
&lt;td&gt;Requires a deliberate strategy on what leaves and where it lives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model Complexity&lt;/td&gt;
&lt;td&gt;Constrained by local hardware&lt;/td&gt;
&lt;td&gt;No practical ceiling, runs the largest and most complex models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational Overhead&lt;/td&gt;
&lt;td&gt;Multiplies with every site added&lt;/td&gt;
&lt;td&gt;Centralized but dependent on connectivity and third-party uptime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The factors rarely pull in the same direction. A workload that demands low latency often generates high data volumes, making cloud impractical on two counts at once. A model complex enough to require cloud compute may involve data that cannot leave the facility. These tensions are where most architecture decisions get made, and where getting the balance right matters most.&lt;/p&gt;
&lt;h2 id=&quot;the-hierarchy-and-where-each-workload-belongs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#the-hierarchy-and-where-each-workload-belongs&quot;&gt;The Hierarchy and Where Each Workload Belongs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The architecture that resolves the edge-vs-cloud question is a five-level hierarchy, one the manufacturing industry already knows. It maps directly to the ISA-95 functional model that has guided industrial operations for decades.&lt;/p&gt;
&lt;p&gt;Each level handles a different class of decisions, at a different speed, with a different scope of data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 0–1 (On-Device):&lt;/strong&gt; Inference runs directly on the sensor, camera, or actuator. Models are small and fast, operating in microseconds with no network involved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 2 (Edge Compute Node):&lt;/strong&gt; Pulls data from multiple machines and runs more capable models across a production cell or line. Keeps working during network outages and syncs upstream when connectivity returns. This level is the most commonly skipped in early planning and the most expensive to add later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 3 (Plant-Level Server):&lt;/strong&gt; Handles facility-wide analytics, MES integration, and the data historian that feeds both local reporting and cloud synchronization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 4–5 (Enterprise and Cloud):&lt;/strong&gt; Where models are trained, retrained, and managed across every site. Latency is not a concern here. Compute depth is.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Diagram showing the ISA-95 five-level hierarchy for industrial AI, from on-device inference at Level 0–1 through edge compute, plant-level server, and enterprise cloud at Level 4–5, with data flowing upward for aggregation and model updates flowing downward to the plant floor&quot; alt=&quot;Diagram showing the ISA-95 five-level hierarchy for industrial AI, from on-device inference at Level 0–1 through edge compute, plant-level server, and enterprise cloud at Level 4–5, with data flowing upward for aggregation and model updates flowing downward to the plant floor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/isa95_flowfuse_final_v4.svg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Data flows up through this hierarchy for aggregation and learning. Model updates, detection thresholds, and configurations flow back down. An architecture that flips this, sending time-sensitive decisions to the cloud while the edge just passes data along, will run into the same problems as a cloud-only deployment, regardless of what it is called.&lt;/p&gt;
&lt;p&gt;Placing workloads correctly is where most industrial AI projects go wrong. The starting point is always the decision itself: what is the AI being asked to do, and what happens if the answer is late? Three questions settle most cases:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What response time is acceptable? Milliseconds point to Level 0–2. Seconds to minutes allow Level 3. Hours or longer can go to the cloud.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Can the data leave the facility? Regulatory constraints, network limitations, or operational policy may make cloud processing impermissible regardless of latency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;How much context does the model need? Single-asset inference fits at the edge. Cross-site pattern recognition belongs in the cloud.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In most real deployments, the same asset feeds multiple levels simultaneously: a Level 2 anomaly detection model acting in real time, a Level 3 shift performance report running every few hours, and a Level 4–5 fleet-wide predictive model retrained monthly. These are three different problems running at three different speeds, not one problem waiting for one answer.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/edge-ai-vs-cloud-ai-in-iiot/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The edge-vs-cloud question has a straightforward answer once the right question is being asked. Not &amp;quot;where should we run our AI?&amp;quot; but &amp;quot;what does this specific workload require, and which level of the hierarchy delivers it?&amp;quot;&lt;/p&gt;
&lt;p&gt;Edge and cloud are not competing philosophies. They are complementary layers of a single architecture that the manufacturing industry already understands. What industrial AI adds is the requirement to place intelligence deliberately at each level, not just data collection at the bottom and reporting at the top, but active inference, model management, and continuous learning distributed across the hierarchy in proportion to where the decisions actually happen.&lt;/p&gt;
&lt;p&gt;The technology to do this exists. The frameworks are mature, the hardware is proven, and the use cases are well established. What separates deployments that deliver sustained operational value from the ones that stall after the pilot is not the sophistication of the models. It is the clarity of the architecture and the discipline to build it in the right order.&lt;/p&gt;
&lt;p&gt;Define the decision. Map it to the hierarchy. Build the infrastructure that decision requires. Then train the model.&lt;/p&gt;
&lt;p&gt;That sequence is what industrial AI at scale actually looks like, and &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is the platform built to run it. From connecting machines and collecting data, to transforming and visualizing it in real time, to running model inference directly in the flow with ONNX nodes, wiring live plant data into AI agents with MCP, and letting operators query their operations in plain language with Expert Insights. One platform. Every level of the hierarchy.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/</id>
        <title>How to Connect to Beckhoff TwinCAT PLC Using ADS (2026)</title>
        <summary>Read and write TwinCAT PLC variables from FlowFuse using the ADS protocol, no additional licensing required.</summary>
        <updated>2026-03-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;By the end you will have live TwinCAT variables flowing into &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you begin, make sure you have the following in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TwinCAT 3.1 runtime running on a Beckhoff IPC&lt;/li&gt;
&lt;li&gt;FlowFuse running on an edge device with network access to the TwinCAT machine. If you don&#39;t have an account yet, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; to get started, then &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;follow this guide to quickly run a FlowFuse instance on your edge device&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Both devices on the same network&lt;/li&gt;
&lt;li&gt;Port 48898 open between the two devices&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#enable-symbol-creation&quot;&gt;Symbol creation&lt;/a&gt; enabled on PlcTask so variables are accessible by name over ADS&lt;/li&gt;
&lt;li&gt;PLC logged in and deployed on port 851&lt;/li&gt;
&lt;li&gt;PLC in Run mode — the TwinCAT system tray icon must be green&lt;/li&gt;
&lt;li&gt;Symbol paths of the variables you want to read or write, available from whoever wrote the PLC program&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;If you don&#39;t have a real PLC available and want to follow along with a test setup, see
&lt;a href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#setting-up-a-test-plc&quot;&gt;Setting Up a Test PLC&lt;/a&gt; at the end of this guide before continuing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-is-ads-and-why-it-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#what-is-ads-and-why-it-matters&quot;&gt;What is ADS and Why It Matters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Every TwinCAT device has an AMS Net ID. It looks like an IP address with two extra octets: &lt;code&gt;10.68.82.232.1.1&lt;/code&gt;. The first four typically match the device IP, the last two are almost always &lt;code&gt;1.1&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;Within a device, different TwinCAT components are reachable on different ADS ports. The PLC runtime listens on port &lt;code&gt;851&lt;/code&gt; by default. If your machine runs multiple PLC tasks, each task gets its own port: the first task is &lt;code&gt;851&lt;/code&gt;, the second is &lt;code&gt;852&lt;/code&gt;, and so on. Check with the controls engineer which port corresponds to the task containing your variables.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;configuring-ads-routes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#configuring-ads-routes&quot;&gt;Configuring ADS Routes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TwinCAT will not accept an ADS connection from an unknown host. Every external device that needs to connect must be explicitly trusted in TwinCAT&#39;s route table. This is stored in a file called &lt;code&gt;StaticRoutes.xml&lt;/code&gt; on the TwinCAT machine.&lt;/p&gt;
&lt;p&gt;TwinCAT provides a route manager in the system tray under &lt;strong&gt;Router &amp;gt; Edit Routes&lt;/strong&gt;. However it does not expose the Flags setting, which defaults to &lt;code&gt;64&lt;/code&gt; and will silently block connections from non-Windows devices such as Linux or Mac based edge devices. Editing &lt;code&gt;StaticRoutes.xml&lt;/code&gt; directly is the only way to set Flags to &lt;code&gt;0&lt;/code&gt;, which allows connections from any trusted device on your network.&lt;/p&gt;
&lt;p&gt;Before adding the route you need two pieces of information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The IP address of your FlowFuse edge device&lt;/li&gt;
&lt;li&gt;The AMS Net ID you will assign to it, which is the IP address with &lt;code&gt;.1.1&lt;/code&gt; appended&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example if your FlowFuse device IP is &lt;code&gt;10.68.82.101&lt;/code&gt;, its AMS Net ID is &lt;code&gt;10.68.82.101.1.1&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Your FlowFuse edge device must be on the same network as the interface TwinCAT&#39;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 &lt;strong&gt;About TwinCAT System&lt;/strong&gt;. Your FlowFuse device must be reachable on that same network, otherwise the ADS handshake will fail even if port 48898 is open.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit StaticRoutes.xml:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;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 &lt;code&gt;Flags&lt;/code&gt; value of &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; The PowerShell command below overwrites the entire &lt;code&gt;StaticRoutes.xml&lt;/code&gt; 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 &lt;code&gt;&amp;lt;RemoteConnections&amp;gt;&lt;/code&gt; block instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;On the TwinCAT machine open PowerShell as administrator&lt;/li&gt;
&lt;li&gt;Run the following command, replacing &lt;code&gt;YOUR_EDGE_DEVICE_IP&lt;/code&gt; with the actual IP of your FlowFuse device:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-134&quot;&gt;
  &lt;pre class=&quot;language-powershell&quot;&gt;&lt;code id=&quot;code-134&quot; class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$xml&lt;/span&gt; = @&lt;span class=&quot;token string&quot;&gt;&quot;&lt;br /&gt;&amp;lt;?xml version=&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;0&lt;span class=&quot;token string&quot;&gt;&quot;?&gt;&lt;br /&gt;&amp;lt;TcConfig xmlns:xsi=&quot;&lt;/span&gt;http:&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;www&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;org/2001/XMLSchema-instance&lt;span class=&quot;token string&quot;&gt;&quot;&gt;&lt;br /&gt;  &amp;lt;RemoteConnections&gt;&lt;br /&gt;    &amp;lt;Route&gt;&lt;br /&gt;      &amp;lt;Name&gt;flowfuse-edge&amp;lt;/Name&gt;&lt;br /&gt;      &amp;lt;Address&gt;YOUR_EDGE_DEVICE_IP&amp;lt;/Address&gt;&lt;br /&gt;      &amp;lt;NetId&gt;YOUR_EDGE_DEVICE_IP.1.1&amp;lt;/NetId&gt;&lt;br /&gt;      &amp;lt;Type&gt;TCP_IP&amp;lt;/Type&gt;&lt;br /&gt;      &amp;lt;Flags&gt;0&amp;lt;/Flags&gt;&lt;br /&gt;    &amp;lt;/Route&gt;&lt;br /&gt;  &amp;lt;/RemoteConnections&gt;&lt;br /&gt;&amp;lt;/TcConfig&gt;&lt;br /&gt;&quot;&lt;/span&gt;@&lt;br /&gt;&lt;span class=&quot;token variable&quot;&gt;$xml&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Set-Content&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C:&#92;Program Files (x86)&#92;Beckhoff&#92;TwinCAT&#92;3.1&#92;Target&#92;StaticRoutes.xml&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-134&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Restart the TwinCAT router from the system tray by right clicking the TwinCAT icon and selecting &lt;strong&gt;Router &amp;gt; Restart&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the Windows Firewall and confirm that port 48898 is allowed for inbound TCP connections.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After the router restarts, verify that port 48898 is reachable from your FlowFuse edge device by running &lt;code&gt;nc -zv &amp;lt;twincat-ip&amp;gt; 48898&lt;/code&gt;. If the connection is refused, confirm the firewall rule was saved and that both devices are on the same subnet.&lt;/p&gt;
&lt;h2 id=&quot;installing-node-red-contrib-ads-client-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#installing-node-red-contrib-ads-client-in-flowfuse&quot;&gt;Installing node-red-contrib-ads-client in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;In your FlowFuse instance open the Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the hamburger menu in the top right and select &lt;strong&gt;Manage Palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-ads-client&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; and wait for it to complete&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Close&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the installation is complete, a few nodes will appear in the right-hand palette under the TwinCAT ADS category.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;TwinCAT ADS nodes available in the Node-RED palette after installing node-red-contrib-ads-client&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/twincat-ads-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;connecting-to-twincat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#connecting-to-twincat&quot;&gt;Connecting to TwinCAT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Add the connection node:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In Node-RED drag an &lt;strong&gt;ADS – Connection Status&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double click it to open the configuration&lt;/li&gt;
&lt;li&gt;Next to the &lt;strong&gt;Connection&lt;/strong&gt; field click &lt;strong&gt;+&lt;/strong&gt; to create a new connection&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Required Settings&lt;/strong&gt; tab fill in the Target AMS Net ID and Target ADS Port:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target AMS Net ID&lt;/td&gt;
&lt;td&gt;AMS Net ID of your TwinCAT machine, e.g. &lt;code&gt;10.68.82.232.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target ADS Port&lt;/td&gt;
&lt;td&gt;&lt;code&gt;851&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Required settings tab showing Target AMS Net ID and Target ADS Port fields in the ADS connection configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Twincat-config-required-fields.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Optional Settings&lt;/strong&gt; tab and fill in the network settings:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Router Address&lt;/td&gt;
&lt;td&gt;IP address of your TwinCAT machine, e.g. &lt;code&gt;10.68.82.232&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Router TCP Port&lt;/td&gt;
&lt;td&gt;&lt;code&gt;48898&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local AMS Net ID&lt;/td&gt;
&lt;td&gt;AMS Net ID of your FlowFuse edge device, e.g. &lt;code&gt;10.68.82.101.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local ADS Port&lt;/td&gt;
&lt;td&gt;&lt;code&gt;32750&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Optional settings tab showing Router Address, Router TCP Port, Local AMS Net ID and Local ADS Port fields&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/twincat-config-optional-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Router Address&lt;/strong&gt; and &lt;strong&gt;Router TCP Port&lt;/strong&gt; allow the ADS client to reach the TwinCAT router over the network. The &lt;strong&gt;Local AMS Net ID&lt;/strong&gt; identifies your FlowFuse edge device inside the ADS routing system and must match the route configured in &lt;code&gt;StaticRoutes.xml&lt;/code&gt;. The &lt;strong&gt;Local ADS Port&lt;/strong&gt; defines the local ADS endpoint used by the client and normally does not need to be changed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your TwinCAT system is in config mode or the PLC runtime takes time to initialize on startup, enable &lt;strong&gt;Allow Half Open&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to save the connection configuration&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Within a few seconds the connection status node should show &lt;strong&gt;connected&lt;/strong&gt;, indicating that FlowFuse successfully established an ADS session with the TwinCAT runtime.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ADS connection status node showing connected state in Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/connection-status.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;reading-plc-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#reading-plc-variables&quot;&gt;Reading PLC Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double click it and leave the default settings so it triggers manually&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;ADS - Read Value&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double click it to configure&lt;/li&gt;
&lt;li&gt;Select your TwinCAT connection from the &lt;strong&gt;Connection&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Variable name&lt;/strong&gt; to the full symbol path of the variable you want to read. Symbol paths are always in the format &lt;code&gt;ProgramName.VariableName&lt;/code&gt;. If you are following along with the test PLC, use &lt;code&gt;MAIN.temperature&lt;/code&gt;. If you are connecting to a real PLC, use the symbol paths provided by the controls engineer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ADS Read Value node configuration showing variable name set to MAIN.temperature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ads-read-value.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the inject node output to the read value node input&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the read value node output to the debug node input&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Click the inject button. You should see the variable value appear in the debug panel.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;wTRmgIyWLyk&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/03/images/ads-read.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Reading TwinCAT PLC Variables with FlowFuse&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;subscribing-to-variable-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#subscribing-to-variable-changes&quot;&gt;Subscribing to Variable Changes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ADS - Subscribe Value&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double click it to configure&lt;/li&gt;
&lt;li&gt;Select your TwinCAT connection from the &lt;strong&gt;Connection&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Variable name&lt;/strong&gt; to the full symbol path of the variable you want to monitor. If you are following along with the test PLC, use &lt;code&gt;MAIN.motorRunning&lt;/code&gt; — it toggles roughly once per second so you will see true and false values arriving in the debug panel without being overwhelmed.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Subscription mode&lt;/strong&gt; to &lt;strong&gt;On Change&lt;/strong&gt;. 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 &lt;strong&gt;Cyclic&lt;/strong&gt; instead.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Cycle time&lt;/strong&gt; to &lt;code&gt;100&lt;/code&gt; milliseconds. This is how frequently TwinCAT checks for changes on its side.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ADS Subscribe Value node configuration showing variable name, subscription mode set to On Change, and cycle time set to 100ms&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ads-subscribe.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Connect its output to a debug node&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The debug node will now receive a message every time the variable value changes in the PLC, with no polling required from FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;JYrzRXCHb9Q&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/03/images/ads-subscribe-image.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Subscribing to TwinCAT PLC Variable Changes with FlowFuse&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;writing-to-plc-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#writing-to-plc-variables&quot;&gt;Writing to PLC Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Writing back to the PLC closes the loop. This is useful for sending setpoints, commands, or reset signals from FlowFuse back to TwinCAT.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ADS - Write Value&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double click it to configure&lt;/li&gt;
&lt;li&gt;Select your TwinCAT connection&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Variable name&lt;/strong&gt; to the full symbol path of the variable you want to write to. If you are following along with the test PLC, use &lt;code&gt;MAIN.setpoint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Leave &lt;strong&gt;Automatically fill missing properties (autoFill)&lt;/strong&gt; 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 &lt;code&gt;MAIN.setpoint&lt;/code&gt; it has no effect.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ADS Write Value node configuration showing variable name set to MAIN.setpoint with autoFill unchecked&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ads-write.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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 &lt;strong&gt;Number&lt;/strong&gt; for INT or REAL, a &lt;strong&gt;boolean&lt;/strong&gt; for BOOL, a &lt;strong&gt;string&lt;/strong&gt; for STRING, and so on. If you are following along with the test PLC, &lt;code&gt;setpoint&lt;/code&gt; is declared as INT so set the payload type to &lt;strong&gt;Number&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the inject node output to the write node input&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the inject button to trigger the write&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To verify the write worked, add a read value node for the same variable and check that the value updated in the debug panel.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;f0GtEp6OA_M&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/03/images/ads-write-image.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Writing to TwinCAT PLC Variables with FlowFuse&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connection fails silently with no error&lt;/strong&gt;
The FlowFuse device IP is not in &lt;code&gt;StaticRoutes.xml&lt;/code&gt; or &lt;code&gt;Flags&lt;/code&gt; is set to &lt;code&gt;64&lt;/code&gt; instead of &lt;code&gt;0&lt;/code&gt;. Edit the file using the PowerShell command in the routing section, then restart the TwinCAT router.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ADS error 7: Target machine not found&lt;/strong&gt;
The most common cause is that your FlowFuse device and the TwinCAT machine are not on the same network as the interface TwinCAT&#39;s AMS Net ID is bound to. Check the AMS Net ID in &lt;strong&gt;About TwinCAT System&lt;/strong&gt; on the TwinCAT machine and confirm your FlowFuse device has an IP on that same subnet. Also confirm the FlowFuse device IP is in &lt;code&gt;StaticRoutes.xml&lt;/code&gt; with &lt;code&gt;Flags&lt;/code&gt; set to &lt;code&gt;0&lt;/code&gt;, and that the router was restarted after any changes. If the PLC runtime takes time to initialize on startup, enable &lt;strong&gt;Allow Half Open&lt;/strong&gt; in the connection node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error: Connection to 127.0.0.1:48898 failed&lt;/strong&gt;
The 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.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error 1808: Symbol not found&lt;/strong&gt;
The 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 &lt;code&gt;MAIN.temperature&lt;/code&gt;. If you are using the test PLC, make sure symbol creation is enabled in PlcTask and the PLC is in Run mode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error 1804: Failed to get fingerprint&lt;/strong&gt;
The FlowFuse device IP is missing from &lt;code&gt;StaticRoutes.xml&lt;/code&gt; or the TwinCAT router was not restarted after editing the file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Port 48898 not reachable&lt;/strong&gt;
Port 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 &lt;code&gt;nc -zv &amp;lt;twincat-ip&amp;gt; 48898&lt;/code&gt; from your FlowFuse device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PLC variables not updating&lt;/strong&gt;
The 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 &lt;strong&gt;Restart TwinCAT (Run Mode)&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setting-up-a-test-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#setting-up-a-test-plc&quot;&gt;Setting Up a Test PLC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;what-you-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#what-you-need&quot;&gt;What You Need&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A Windows machine or laptop&lt;/li&gt;
&lt;li&gt;TwinCAT XAE Shell installed. Download it from the &lt;a href=&quot;https://www.beckhoff.com/&quot;&gt;Beckhoff website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;create-the-project&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#create-the-project&quot;&gt;Create the Project&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open TwinCAT XAE Shell&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;File &amp;gt; New &amp;gt; Project&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;TwinCAT Projects&lt;/strong&gt; then &lt;strong&gt;TwinCAT XAE Project&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Give the project a name, for example &lt;code&gt;AdsDemo&lt;/code&gt;, and click &lt;strong&gt;OK&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;add-a-plc-project&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#add-a-plc-project&quot;&gt;Add a PLC Project&lt;/a&gt;&lt;/h3&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;In Solution Explorer right click the project name and select &lt;strong&gt;Add New Item&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Standard PLC Project&lt;/strong&gt;, give it a name, and click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;write-the-plc-program&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#write-the-plc-program&quot;&gt;Write the PLC Program&lt;/a&gt;&lt;/h3&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;In Solution Explorer expand &lt;strong&gt;PLC &amp;gt; your project &amp;gt; POUs&lt;/strong&gt; and double click &lt;strong&gt;MAIN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the declaration section (top panel) replace the existing content with:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;PROGRAM MAIN
VAR
    temperature : REAL := 23.5;
    motorRunning : BOOL := FALSE;
    setpoint : INT := 100;
    cycleCount : INT := 0;
END_VAR
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;In the program body (bottom panel) add:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;temperature := temperature + 0.1;
IF temperature &amp;gt; 100.0 THEN
    temperature := 0.0;
END_IF

cycleCount := cycleCount + 1;
IF cycleCount &amp;gt;= 1000 THEN
    motorRunning := NOT motorRunning;
    cycleCount := 0;
END_IF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives you three live variables to work with. &lt;code&gt;temperature&lt;/code&gt; increments continuously every PLC cycle, &lt;code&gt;motorRunning&lt;/code&gt; toggles roughly once per second, and &lt;code&gt;setpoint&lt;/code&gt; stays static until you write to it from FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;enable-symbol-creation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#enable-symbol-creation&quot;&gt;Enable Symbol Creation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;In Solution Explorer expand the project, then under &lt;strong&gt;Task&lt;/strong&gt; double click &lt;strong&gt;PlcTask&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Create symbols&lt;/strong&gt; in the properties window that opens&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;PlcTask properties window showing the Create symbols checkbox enabled&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/create-symbol.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;build-and-activate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#build-and-activate&quot;&gt;Build and Activate&lt;/a&gt;&lt;/h3&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Press &lt;strong&gt;Ctrl+Shift+B&lt;/strong&gt; to build the project. Check the output window for any errors before continuing.&lt;/li&gt;
&lt;li&gt;Right click the PLC instance in Solution Explorer and select &lt;strong&gt;Login&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If Login is not visible in the right click menu, find it in the top menu bar under &lt;strong&gt;PLC &amp;gt; Login&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;15&quot;&gt;
&lt;li&gt;When TwinCAT prompts you to create the application on port 851, click &lt;strong&gt;Yes&lt;/strong&gt;. Do not skip this step or change the port.&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;F5&lt;/strong&gt; to start the PLC&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Your test PLC is now running. Go back to the &lt;a href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#configuring-ads-routes&quot;&gt;Configuring ADS Routes&lt;/a&gt; section and continue from there. The variable paths you will use throughout this guide are &lt;code&gt;MAIN.temperature&lt;/code&gt;, &lt;code&gt;MAIN.motorRunning&lt;/code&gt;, and &lt;code&gt;MAIN.setpoint&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-connect-to-twincat-using-ads/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;This guide covered the core nodes to get you connected and working. The &lt;code&gt;node-red-contrib-ads-client&lt;/code&gt; package includes several other nodes worth exploring on your own, and future articles will cover more advanced use cases in depth.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/</id>
        <title>FlowFuse 2.28: Troubleshoot Faster, Manage Edge Devices Centrally, and More Self-Hosted Flexibility</title>
        <summary>Point FlowFuse Expert at your debug logs, configure Node.js runtime options for edge devices, and gain more control over self-hosted deployments.</summary>
        <updated>2026-03-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/"/>
        <author><name>Dimitrie Hoekstra</name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.28 focuses on making your day-to-day work faster and giving you more control — whether you are debugging a flow, managing edge devices, or running FlowFuse on your own infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;troubleshoot-flows-faster-with-flowfuse-expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#troubleshoot-flows-faster-with-flowfuse-expert&quot;&gt;Troubleshoot Flows Faster with FlowFuse Expert&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tracking down issues in your flows usually means adding debug nodes, reading through log output, and then trying to describe the problem to get help. That back-and-forth slows you down.&lt;/p&gt;
&lt;h3 id=&quot;point-expert-at-your-debug-logs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#point-expert-at-your-debug-logs&quot;&gt;Point Expert at Your Debug Logs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can now select individual debug log entries and include them as context when asking FlowFuse Expert for help. Combined with your selected flows, Expert sees exactly what you see — the error, the flow that produced it, and the surrounding context.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;e0XV6lMKazo&quot; params=&quot;rel=0&quot; style=&quot;width: 704; height: 100%; background-image: url(&#39;https://img.youtube.com/vi/e0XV6lMKazo/maxresdefault.jpg&#39;);&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;figcaption&gt;Select specific log entries to give FlowFuse Expert focused troubleshooting context&lt;/figcaption&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Select individual log entries&lt;/strong&gt; to focus Expert on the specific issue rather than everything in your log&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quick-add from the Resource Selector&lt;/strong&gt; to pull in logs alongside your flows in one step&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get targeted answers&lt;/strong&gt; because Expert reasons about your actual errors, not a description of them&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;always-have-the-latest-expert-capabilities&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#always-have-the-latest-expert-capabilities&quot;&gt;Always Have the Latest Expert Capabilities&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Expert is getting new capabilities regularly — like the debug log context above. But when you are deep in your flows, it is easy to miss that an update is available. Expert now shows a banner when a newer version is ready. One click and you are up to date, so you always have access to the latest troubleshooting and development features.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img style=&quot;border: 2px solid #E5E7EB;&quot; data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert update banner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/expert-update-banner.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Expert lets you know when an update is available&lt;/figcaption&gt;
&lt;h2 id=&quot;new-device-agent-configuration-options&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#new-device-agent-configuration-options&quot;&gt;New Device Agent Configuration Options&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse 2.28 combined with Device Agent v3.8.1 expands what you can configure on your edge devices, giving you more control over how Node-RED runs on Remote Instances.&lt;/p&gt;
&lt;h3 id=&quot;configure-node.js-runtime-options&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#configure-node.js-runtime-options&quot;&gt;Configure Node.js Runtime Options&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The latest Device Agent lets you set Node.js command line arguments for Remote Instances — via your &lt;code&gt;device.yml&lt;/code&gt; or the agent command line. Previously these options were not configurable at all. The full set of NodeJS (command line arguments)[https://nodejs.org/docs/latest-v22.x/api/cli.html] can be set. For example&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Increase memory&lt;/strong&gt; for flows that process large datasets (&lt;code&gt;--max-old-space-size&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;set-api-payload-limits-from-the-ui&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#set-api-payload-limits-from-the-ui&quot;&gt;Set API Payload Limits from the UI&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your Remote Instances handle large file uploads, you may have hit the default API payload size limit. You can now configure the maximum API payload length directly in FlowFuse under &lt;strong&gt;Remote Instance → Settings → Editor&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-flexibility-for-self-hosted-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#more-flexibility-for-self-hosted-deployments&quot;&gt;More Flexibility for Self-Hosted Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;migrate-from-ingress-nginx-to-traefik&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#migrate-from-ingress-nginx-to-traefik&quot;&gt;Migrate from Ingress Nginx to Traefik&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the &lt;a href=&quot;https://kubernetes.io/blog/2025/06/30/ingress-nginx-retirement/&quot;&gt;retirement of Ingress Nginx&lt;/a&gt;, many self-hosted Kubernetes users need to move to a supported ingress controller. To help with this transition, we have prepared a blueprint for migrating from Ingress Nginx to Traefik. The Helm chart now includes the required job resources and RBAC for the migration tool, and we have published a step-by-step &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/ingress-controller-migration/&quot;&gt;ingress controller migration guide&lt;/a&gt; to walk you through the process.&lt;/p&gt;
&lt;p&gt;As part of this work, you can now also set a separate ingress class name for Hosted Instances using &lt;code&gt;forge.projectIngressClassName&lt;/code&gt;, allowing you to run project traffic through a different ingress controller than the platform itself.&lt;/p&gt;
&lt;h3 id=&quot;additional-self-hosted-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#additional-self-hosted-improvements&quot;&gt;Additional self-hosted improvements&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Team NPM Registry&lt;/strong&gt; — Docker Compose deployments can now have all the Team Library, Custom Nodes pre-requisits configured.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File-server PVC configuration&lt;/strong&gt; — Set the size, access modes, and storage class for file-server persistent volumes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private CA certificate mounting&lt;/strong&gt; — Docker Compose deployments can now mount a private CA certificate file into the forge service&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Instances can now automatically receive scheduled maintenance, so they stay up to date without manual configuration.&lt;/li&gt;
&lt;li&gt;Updated FlowFuse Expert documentation with dedicated guides for the Chat Interface and AI-assisted features in Node-RED&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For detailed breakdowns of each feature with additional visuals, visit our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;changelog&lt;/a&gt;. For the complete list of everything included in FlowFuse 2.28, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If something in this release improves your workflow, or if there is still friction we can remove, please &lt;a href=&quot;mailto:contact@flowfuse.com?subject=Feedback%20on%202.28/&quot;&gt;share feedback or report issues regarding this release&lt;/a&gt; to us.&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The fastest way to get started is with FlowFuse Cloud.
&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/flowfuse-release-2-28/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run FlowFuse locally using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/last-mile-problem-ai/</id>
        <title>The Last Mile Problem in Industrial AI</title>
        <summary>You approved the budget. The model works. So why is it still in staging?</summary>
        <updated>2026-03-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/last-mile-problem-ai/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;There is a slide that lives in almost every industrial AI project deck.&lt;/p&gt;
&lt;p&gt;On the left: data collection, model training, validation. On the right: operational value, reduced downtime, optimized throughput. In the middle, a small box labeled &amp;quot;deployment&amp;quot; that nobody in the room questions, because everyone has already moved on to the numbers on the right.&lt;/p&gt;
&lt;p&gt;That box is where most industrial AI projects end.&lt;/p&gt;
&lt;p&gt;Not with a failure report. Not with a cancelled contract. They end slowly, in staging environments that quietly become permanent, in quarterly reviews where &amp;quot;ongoing&amp;quot; gets said for the fourth time with less conviction than the third. The model is fine. The model has always been fine. The floor looks exactly the same as it did before the project started.&lt;/p&gt;
&lt;p&gt;What lives inside that box is harder than the model and less interesting to talk about. It is the work of connecting intelligent software to a plant that was not built to receive it. Machines that predate wireless. Protocols designed for reliability, not interoperability. Engineers who know every quirk of every line and have watched enough consultants walk through with laptops to reserve judgment until something actually works.&lt;/p&gt;
&lt;p&gt;In logistics, the last mile is the final stretch of a delivery, the leg that accounts for more than half the cost of shipping and has defeated every attempt to engineer it away. Industrial AI has the same problem. Not measured in distance. Measured in the gap between a model that performs and a plant that benefits.&lt;/p&gt;
&lt;p&gt;Most industrial AI projects are funded to build the model. The mile after it gets a box on a slide.&lt;/p&gt;
&lt;h2 id=&quot;the-scoping-lie&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/last-mile-problem-ai/#the-scoping-lie&quot;&gt;The Scoping Lie&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every industrial AI project proposal looks roughly the same.&lt;/p&gt;
&lt;p&gt;There is a discovery phase. A data assessment. A model development stage with clear milestones and measurable accuracy targets. And then, near the bottom of the document, a deployment section that is usually one page, sometimes half a page, occasionally a single bullet point that says something like &amp;quot;integration with existing systems&amp;quot; without specifying which systems, how long that will take, or who is responsible for it.&lt;/p&gt;
&lt;p&gt;That bullet point is where the project dies. It just takes six months to find out.&lt;/p&gt;
&lt;p&gt;The people writing these proposals are not being dishonest. They are being optimistic in the way that every vendor is optimistic when the contract has not been signed yet. The integration work is real, they know it is real, but it is also the part of the project that is hardest to scope without knowing the plant, the protocols, the historian configuration, the network topology, the IT security policies, and a dozen other variables that only become visible once someone is standing on the floor with access credentials and a growing sense of unease.&lt;/p&gt;
&lt;p&gt;So it gets compressed. One line. One assumption. One box on a slide.&lt;/p&gt;
&lt;p&gt;And the buyer approves it, because the buyer is looking at the numbers on the right side of the timeline, the ones showing reduced downtime and optimized throughput, and the deployment box is between them and those numbers, and it looks small.&lt;/p&gt;
&lt;p&gt;It is not small.&lt;/p&gt;
&lt;p&gt;The integration work in a real industrial environment is not a technical footnote. It is the project. Connecting an AI model to a plant means touching systems that the OT team has kept stable for a decade and does not want anyone near. It means translating between protocols that were never designed to talk to each other. It means getting IT and OT into the same room, agreeing on data ownership, network access, security boundaries, and update procedures for infrastructure that both teams think belongs to the other.&lt;/p&gt;
&lt;p&gt;None of that is in the proposal. All of it determines whether the proposal was worth signing.&lt;/p&gt;
&lt;h2 id=&quot;the-cost-of-standing-still&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/last-mile-problem-ai/#the-cost-of-standing-still&quot;&gt;The Cost of Standing Still&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pilot purgatory feels like a neutral state. The project is not cancelled. Progress is being made. The model is ready whenever the integration catches up.&lt;/p&gt;
&lt;p&gt;It is not neutral.&lt;/p&gt;
&lt;p&gt;Every month an AI model sits in staging is a month of decisions made on instinct instead of intelligence. A predictive maintenance model that never reached the floor did not just fail to deliver value. It failed to prevent every unplanned downtime event it would have caught. Every quality escape the anomaly detector would have flagged. Every maintenance window scheduled too late or too early because the optimization model was still &amp;quot;ongoing.&amp;quot;&lt;/p&gt;
&lt;p&gt;That cost does not appear in any project report. It is invisible precisely because the thing that would have measured it never got deployed. But it is real, and it compounds.&lt;/p&gt;
&lt;p&gt;Every stalled initiative also makes the next one harder to fund. The VP who approved the last pilot is not writing another check with the same enthusiasm. The organizational appetite for transformation is not infinite. Stalled pilots consume it without producing anything in return.&lt;/p&gt;
&lt;h2 id=&quot;the-ownership-vacuum&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/last-mile-problem-ai/#the-ownership-vacuum&quot;&gt;The Ownership Vacuum&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is a question worth asking before the next industrial AI project gets funded.&lt;/p&gt;
&lt;p&gt;When the model is in production and something goes wrong at 2 a.m. on a Saturday, who gets the call?&lt;/p&gt;
&lt;p&gt;In most manufacturing organizations, nobody has a clean answer to that. The data science team built the model but does not own the plant systems it connects to. The OT team owns the plant but did not build the model and does not have visibility into why it is behaving the way it is. IT owns the network the data travels across but considers the edge devices an OT problem. Nobody owns the pipeline between them.&lt;/p&gt;
&lt;p&gt;This is not a technology problem. It is a leadership problem that has been dressed up as one.&lt;/p&gt;
&lt;p&gt;The technology gap between a trained model and a production deployment is real, but it is solvable. Talented engineers solve harder problems every day. What stops them is not the complexity of the integration. It is the absence of anyone whose job it is to own the outcome. When the integration work falls between two teams and neither team has it in their objectives, it does not get done. It gets discussed. It gets escalated. It gets added to the agenda of a cross-functional meeting that gets rescheduled twice and then produces a decision to form a working group.&lt;/p&gt;
&lt;p&gt;Meanwhile the model sits in staging.&lt;/p&gt;
&lt;p&gt;The IT/OT divide gets talked about as a technical challenge, a matter of protocols and network segmentation and data formats. Those things are real. But the deeper divide is organizational. Two teams, built for different purposes, measured on different outcomes, reporting to different leaders, looking at the same plant and seeing completely different problems. IT sees a security perimeter to protect. OT sees uptime to defend. Neither is wrong. Neither is looking at the gap between them.&lt;/p&gt;
&lt;p&gt;That gap does not close itself. It closes when someone in the organization is explicitly responsible for closing it, with the authority to make decisions across both teams and the mandate to finish what the project started.&lt;/p&gt;
&lt;p&gt;Most industrial AI initiatives are not structured that way. The project has a data science lead and a project manager and a steering committee. It does not have an integration owner. And so the last mile, the mile that requires both teams to move toward each other, stays exactly as wide as it was on day one.&lt;/p&gt;
&lt;h2 id=&quot;what-closing-the-last-mile-actually-requires&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/last-mile-problem-ai/#what-closing-the-last-mile-actually-requires&quot;&gt;What Closing the Last Mile Actually Requires&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The answer is not a better model. It is not a bigger data science team. It is not another vendor promising that this time the integration will be straightforward.&lt;/p&gt;
&lt;p&gt;It is infrastructure. Built deliberately, before the model needs it, designed for the environment it will actually run in.&lt;/p&gt;
&lt;p&gt;That means starting with connectivity that meets the plant where it is, not where the vendor deck imagines it to be. Real plants run Modbus, OPC-UA, Siemens S7, proprietary historian formats, and protocols that were old before most current software engineers started their careers. The integration layer has to speak all of it, fluently, without requiring the OT team to replace equipment that is working perfectly and will continue working perfectly for another decade.&lt;/p&gt;
&lt;p&gt;It means edge execution that does not depend on the cloud. A prediction that requires a round trip to a cloud inference endpoint is a prediction that fails the moment the network hiccups, which in a manufacturing environment is not a rare event. Intelligence needs to run close to the equipment it is monitoring, locally, with enough resilience to keep functioning when connectivity is degraded and enough security to satisfy the IT team that approved it onto the network.&lt;/p&gt;
&lt;p&gt;It means deployment infrastructure that OT teams can actually own. The data scientist who trained the model will not be available at 2 a.m. on a Saturday. The update that fixes the drift in the anomaly detector cannot wait for a change request to clear a two-week approval queue. The people running the plant need to be able to deploy, update, monitor, and roll back AI systems through tooling that respects their domain knowledge without demanding software development skills they were never hired to have.&lt;/p&gt;
&lt;p&gt;And it means governance that scales across facilities from the beginning. One plant is a pilot. Twelve plants is a program. The infrastructure that works for one site needs to work for all of them, with consistent versioning, auditable change history, role-based access, and the ability to push a validated update across a fleet without touching each device individually. Organizations that build for one site and retrofit for scale spend years rebuilding what they should have built once.&lt;/p&gt;
&lt;p&gt;This is what the proposal compressed into a single box on a slide. Not one problem. Four interconnected ones, each of which can stop a deployment on its own, all of which need to be solved together before the model delivers anything.&lt;/p&gt;
&lt;h2 id=&quot;the-mile-is-closable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/last-mile-problem-ai/#the-mile-is-closable&quot;&gt;The Mile Is Closable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last mile problem in industrial AI is not a technology problem waiting for a breakthrough. The technology exists. The manufacturers still stuck in pilot purgatory cannot blame the tools.&lt;/p&gt;
&lt;p&gt;It is a prioritization problem. A scoping problem. A decision, made early in every project, about what the work actually is and what it will take to finish it.&lt;/p&gt;
&lt;p&gt;The manufacturers generating real operational value from AI today made a different decision. They treated integration as the foundation, not the footnote. They gave the last mile the budget it deserved, the ownership it required, and the infrastructure it needed to hold. And then they built models on top of that foundation and watched them actually run.&lt;/p&gt;
&lt;p&gt;That is the sequence. Infrastructure first. Intelligence on top of it. Not the other way around.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/</id>
        <title>How to Stop Silent Pipeline Failures From Swallowing Your IIoT Data</title>
        <summary>When your pipeline fails, every dropped message is data you&#39;ll never get back, until now</summary>
        <updated>2026-03-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Somewhere in your IIoT pipeline, a message just failed. You don&#39;t know which one. You don&#39;t know when. And unless you have a Dead Letter Queue, you never will.&lt;/p&gt;
&lt;p&gt;In industrial environments, failure is not the exception. It is the contract. Networks partition. APIs rate-limit. A sensor alert fires at the wrong moment and vanishes without a trace. And unlike consumer applications, missed messages in manufacturing have a real cost.&lt;/p&gt;
&lt;p&gt;That cost is invisible by default. No error surface. No audit trail. Just data that was there and then wasn&#39;t. FlowFuse changes that. It gives your IIoT pipelines the production-grade tooling they need to handle failure the right way: catch it, retry it, and preserve everything that couldn&#39;t be recovered so you can act on it later.&lt;/p&gt;
&lt;p&gt;This guide shows you how to build exactly that. You will walk away with a production-ready pattern for catching failed messages, retrying them with exponential backoff, and routing the unrecoverable ones into a Dead Letter Queue where they can be inspected, replayed, or discarded on your terms.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-dead-letter-queue%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#what-is-a-dead-letter-queue%3F&quot;&gt;What Is a Dead Letter Queue?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Dead Letter Queue is a holding area for messages that could not be delivered. When a message fails processing and has no path forward, it gets routed to the DLQ instead of being dropped or causing your flow to crash.&lt;/p&gt;
&lt;p&gt;A message ends up in a DLQ for four reasons. It exceeded the maximum number of retry attempts. It is malformed and cannot be parsed. The target system is permanently unavailable. Or a business rule explicitly rejected it.&lt;/p&gt;
&lt;p&gt;The value of a DLQ is not just storage. It is observability. Every failed message arrives with its full payload, error reason, retry history, and timestamps intact. You know exactly what failed, when it failed, and how many times it was attempted before giving up. That information is what makes recovery possible.&lt;/p&gt;
&lt;p&gt;Without a DLQ, failed messages disappear silently. With one, failure becomes something you can inspect, act on, and fix.&lt;/p&gt;
&lt;h2 id=&quot;the-retry-pattern%3A-exponential-backoff&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#the-retry-pattern%3A-exponential-backoff&quot;&gt;The Retry Pattern: Exponential Backoff&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before a message earns its place in the DLQ, you should try, and try again. But naive retries are dangerous. Hammering a failing service every 100ms does not give it time to recover. It makes things worse for everyone.&lt;/p&gt;
&lt;p&gt;The industry standard is &lt;strong&gt;exponential backoff with jitter&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;delay = min(base * 2^attempt, max_delay) + random_jitter
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attempt&lt;/th&gt;
&lt;th&gt;Base Delay&lt;/th&gt;
&lt;th&gt;With Jitter (approx.)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1s&lt;/td&gt;
&lt;td&gt;1.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2s&lt;/td&gt;
&lt;td&gt;2.5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4s&lt;/td&gt;
&lt;td&gt;4.1s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8s&lt;/td&gt;
&lt;td&gt;8.9s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;→ DLQ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The jitter prevents the &lt;strong&gt;thundering herd problem&lt;/strong&gt;, where every failed client retries at exactly the same moment and overloads the service all over again.&lt;/p&gt;
&lt;h2 id=&quot;building-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#building-it&quot;&gt;Building It&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we&#39;ll build this pattern in FlowFuse step by step.&lt;/p&gt;
&lt;p&gt;FlowFuse is the Industrial Application Platform that connects any machine or system, collects data across any protocol, and lets you act on it at production scale, with enterprise features like role-based access control, centralized device management, audit logging, and team collaboration built in. It also includes FlowFuse Tables, a built-in database service that gives all your instances a single shared DLQ, so every failed message across your entire fleet lands in one place, visible and queryable from anywhere. &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us&lt;/a&gt; to get started.&lt;/p&gt;
&lt;p&gt;The architecture has five components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Retry state initializer&lt;/li&gt;
&lt;li&gt;Catch node for centralized error handling&lt;/li&gt;
&lt;li&gt;Retry manager with exponential backoff&lt;/li&gt;
&lt;li&gt;Delay node for controlled retries&lt;/li&gt;
&lt;li&gt;Dead Letter Queue backed by FlowFuse Tables&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s how they connect:&lt;/p&gt;
&lt;pre class=&quot;mermaid&quot;&gt;flowchart TD&amp;#10;    A[Input] --&amp;gt; B[Process]&amp;#10;    B --&amp;gt; C[Success Handler]&amp;#10;    B --&amp;gt;|on error| D[Retry Manager]&amp;#10;    D --&amp;gt;|within max retries| E[Delay]&amp;#10;    E --&amp;gt; B&amp;#10;    D --&amp;gt;|max retries exceeded| F[Dead Letter Queue]&amp;#10;    linkStyle default stroke:#4F46E5,stroke-width:2px&amp;#10;    style A fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;    style B fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;    style C fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;    style D fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;    style E fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;    style F fill:#ffffff,color:#4B5563,stroke:#4F46E5&amp;#10;&lt;/pre&gt;
&lt;p&gt;Every step below maps directly to one part of that diagram. Follow it in order.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-initialize-retry-state&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#step-1%3A-initialize-retry-state&quot;&gt;Step 1: Initialize Retry State&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This function node runs once when a fresh message enters the pipeline. It attaches retry metadata to &lt;code&gt;msg&lt;/code&gt; so every downstream node knows where the message stands.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;Init Retry State&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Function&lt;/strong&gt; tab, paste the following code:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-186&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-186&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_originalPayload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cloneMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_retry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_retry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;attempts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;maxAttempts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;lastError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;originalTimestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-186&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Two things are happening here worth noting. First, &lt;code&gt;msg._originalPayload&lt;/code&gt; saves a deep clone of the original payload using &lt;code&gt;RED.util.cloneMessage&lt;/code&gt; before anything touches it. A plain assignment (&lt;code&gt;= msg.payload&lt;/code&gt;) would only copy a reference. If a downstream node mutates the object in place, the saved copy changes too. &lt;code&gt;cloneMessage&lt;/code&gt; ensures the DLQ always holds the payload exactly as it arrived. Some nodes, like the HTTP Request node, also overwrite &lt;code&gt;msg.payload&lt;/code&gt; with their response body, so this clone is what gets stored in the DLQ later. Second, the &lt;code&gt;if (!msg._retry)&lt;/code&gt; check ensures initialization only runs on a fresh message. When the retry loop sends the message back through, this block is skipped entirely and the existing retry state is preserved. The underscore prefix on &lt;code&gt;msg._retry&lt;/code&gt; also protects it from being overwritten by processing nodes.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-add-a-catch-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#step-2%3A-add-a-catch-node&quot;&gt;Step 2: Add a Catch Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The catch node monitors your processing nodes and intercepts any message that causes an error, routing it to the retry logic instead of letting it disappear.&lt;/p&gt;
&lt;p&gt;Scoping it to &lt;code&gt;All nodes&lt;/code&gt; is tempting but dangerous. If any node in the retry infrastructure itself throws, for example the Retry Manager calling &lt;code&gt;node.error()&lt;/code&gt;, the catch node will intercept it and feed it back into the retry loop, creating an infinite loop. Scoping it explicitly to your processing nodes prevents this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;catch node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;Catch Errors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Catch errors from&lt;/strong&gt; to &lt;code&gt;Selected nodes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select only the nodes where real failures can occur. In practice, these are the nodes that talk to the outside world: MQTT nodes, HTTP request nodes, database nodes, WebSocket nodes, or anything that reaches beyond the flow itself. Taking the example flow provided at the end of this guide, that means selecting the HTTP Request node and the Check Response function node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next, add a normalization step between the catch node and the retry manager. Built-in nodes sometimes attach &lt;code&gt;msg.error&lt;/code&gt; as an object rather than a string, which causes problems downstream. This function node converts it to a consistent string format.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;Normalize Error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Function&lt;/strong&gt; tab, paste:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-263&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-263&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_retry&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;object&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Processing failed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-263&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wire the &lt;strong&gt;catch node&lt;/strong&gt; output to the &lt;strong&gt;Normalize Error&lt;/strong&gt; input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-3%3A-add-the-retry-manager&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#step-3%3A-add-the-retry-manager&quot;&gt;Step 3: Add the Retry Manager&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the decision node. It increments the attempt count, calculates the backoff delay, and routes the message either back into the pipeline for another try or forward to the DLQ if retries are exhausted.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;Retry Manager&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Setup&lt;/strong&gt; tab and set &lt;strong&gt;Outputs&lt;/strong&gt; to &lt;code&gt;2&lt;/code&gt;. This gives the node two output ports, one for retrying and one for the DLQ.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Function&lt;/strong&gt; tab and paste:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-309&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-309&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_ATTEMPTS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxAttempts &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BASE_DELAY_MS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_DELAY_MS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastError &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Unknown error&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastAttemptAt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// keep _retry in sync&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_retry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_ATTEMPTS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exhausted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dlq &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Max retries exceeded&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;attempts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attempts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;lastError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;deadAt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; exponential &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;BASE_DELAY_MS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jitter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exponential &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; jitter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_DELAY_MS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;yellow&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ring&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Retry &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;retry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attempts&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_ATTEMPTS&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; in &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-309&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wire the &lt;strong&gt;Normalize Error&lt;/strong&gt; output to the &lt;strong&gt;Retry Manager&lt;/strong&gt; input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;return [msg, null]&lt;/code&gt; sends the message out of &lt;strong&gt;Output 1&lt;/strong&gt; (retry path). &lt;code&gt;return [null, msg]&lt;/code&gt; sends it out of &lt;strong&gt;Output 2&lt;/strong&gt; (DLQ path). No switch node is needed. The routing is built into the return statement.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-add-the-delay-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#step-4%3A-add-the-delay-node&quot;&gt;Step 4: Add the Delay Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The delay node holds the message for the calculated backoff period before it re-enters the pipeline. Without this, retries fire instantly and you are hammering an already-struggling service.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;delay node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;Backoff Delay&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Action&lt;/strong&gt; to &lt;code&gt;Delay each message&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;For&lt;/strong&gt; to &lt;code&gt;Override delay with msg.delay&lt;/code&gt;. This tells the node to use the backoff value the Retry Manager calculated rather than a fixed duration.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wire &lt;strong&gt;Retry Manager Output 1&lt;/strong&gt; to &lt;strong&gt;Backoff Delay&lt;/strong&gt; input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each pass through the loop, the delay gets longer. Roughly 1 second on the first retry, 2 seconds on the second, 4 on the third, and so on. When the Retry Manager decides retries are exhausted, it stops sending to Output 1 entirely and routes to Output 2 instead, ending the loop.&lt;/p&gt;
&lt;p&gt;Wire &lt;strong&gt;Backoff Delay&lt;/strong&gt; output to your processing node input. This completes the retry loop.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-set-up-the-dlq-handler&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#step-5%3A-set-up-the-dlq-handler&quot;&gt;Step 5: Set Up the DLQ Handler&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When a message reaches this stage, retries are finished. The goal now is to preserve everything: the original payload, the error reason, how many attempts were made, and the timestamp. That context is what makes later recovery possible. Without a persistent store, that context disappears the moment the flow restarts, the device reboots, or the pipeline moves on to the next message. And in a multi-instance deployment, you need a store that is accessible across every instance in your fleet, not just the device the failure happened on.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/&quot;&gt;FlowFuse Tables&lt;/a&gt; gives you exactly that: a managed PostgreSQL database that connects directly to your flows with no credentials to configure and no external infrastructure to manage, making it the right storage layer for a production DLQ.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; FlowFuse Tables requires an Enterprise plan.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;5a%3A-create-the-dlq-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#5a%3A-create-the-dlq-table&quot;&gt;5a: Create the DLQ Table&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;In FlowFuse, go to &lt;strong&gt;Team Settings&lt;/strong&gt; and &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#step-1%3A-enable-the-database-in-your-project&quot;&gt;enable the Tables feature&lt;/a&gt; for your team.&lt;/li&gt;
&lt;li&gt;Once enabled, drag a &lt;strong&gt;Query node&lt;/strong&gt; from the FlowFuse category onto the canvas.&lt;/li&gt;
&lt;li&gt;The Query node is pre-configured to connect to your FlowFuse-managed database automatically. No credentials needed.&lt;/li&gt;
&lt;li&gt;Paste the following into the Query field:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-413&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-413&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dlq&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;topic&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;attempts&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;last_error&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;captured_at&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-413&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Connect an &lt;strong&gt;Inject node&lt;/strong&gt; set to run once on deploy to the Query node input.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you prefer, you can also create the table directly from the &lt;strong&gt;Tables&lt;/strong&gt; section in the FlowFuse navigation without writing any SQL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;5b%3A-build-the-insert-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#5b%3A-build-the-insert-flow&quot;&gt;5b: Build the Insert Flow&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; onto the canvas and name it &lt;code&gt;Build DLQ Params&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following rules:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Value type&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;msg&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_msgid&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.topic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;msg&lt;/td&gt;
&lt;td&gt;&lt;code&gt;retry.topic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSONata&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$string(_originalPayload)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.attempts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;msg&lt;/td&gt;
&lt;td&gt;&lt;code&gt;retry.attempts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.last_error&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;msg&lt;/td&gt;
&lt;td&gt;&lt;code&gt;retry.lastError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msg.queryParameters.captured_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSONata&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$now()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Query node&lt;/strong&gt; from the FlowFuse category onto the canvas and name it &lt;code&gt;Insert DLQ Record&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the following SQL:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-576&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-576&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dlq&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;topic&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;attempts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last_error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;captured_at&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $attempts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $last_error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $captured_at&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; CONFLICT &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;attempts&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; EXCLUDED&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;attempts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;last_error&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; EXCLUDED&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;last_error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;captured_at&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; EXCLUDED&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;captured_at&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-576&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Wire &lt;strong&gt;Retry Manager Output 2&lt;/strong&gt; to &lt;strong&gt;Build DLQ Params&lt;/strong&gt;, then &lt;strong&gt;Build DLQ Params&lt;/strong&gt; to &lt;strong&gt;Insert DLQ Record&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;ON CONFLICT DO UPDATE&lt;/code&gt; ensures a message that appears multiple times does not create duplicate rows. It updates cleanly on the same &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together%3A-simulation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#putting-it-all-together%3A-simulation&quot;&gt;Putting It All Together: Simulation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best way to understand the pattern is to watch it work. This simulation models a temperature sensor publishing readings to an HTTP API every 5 seconds. The mock API is deliberately configured to fail 80% of the time so you can watch the full cycle in action: messages attempting delivery, retrying with increasing delays, and after 5 failed attempts landing permanently in FlowFuse Tables.&lt;/p&gt;
&lt;p&gt;Import the flow below directly into FlowFuse. It contains everything: the sensor data simulator, the mock API, the retry logic, the DLQ handler, and a query button to inspect what landed in the database.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In the simulation, the retry state initialization from Step 1 is folded directly into the &lt;strong&gt;Simulate Reading&lt;/strong&gt; function node rather than existing as a separate node. In a real deployment you would keep them separate as described in the tutorial.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div id=&quot;nr-flow-256&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow256 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;3f70e1b09c698a8b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;676f468a5eacf480&#92;&quot;,&#92;&quot;f24fcdcd3c682474&#92;&quot;],&#92;&quot;x&#92;&quot;:174,&#92;&quot;y&#92;&quot;:239,&#92;&quot;w&#92;&quot;:572,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;676f468a5eacf480&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f70e1b09c698a8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table on Deploy&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f24fcdcd3c682474&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f24fcdcd3c682474&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f70e1b09c698a8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create DLQ Table&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS &#92;&#92;&#92;&quot;dlq&#92;&#92;&#92;&quot; (&#92;&#92;n  &#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot; TEXT PRIMARY KEY,&#92;&#92;n  &#92;&#92;&#92;&quot;topic&#92;&#92;&#92;&quot; TEXT,&#92;&#92;n  &#92;&#92;&#92;&quot;payload&#92;&#92;&#92;&quot; TEXT,&#92;&#92;n  &#92;&#92;&#92;&quot;attempts&#92;&#92;&#92;&quot; INTEGER,&#92;&#92;n  &#92;&#92;&#92;&quot;last_error&#92;&#92;&#92;&quot; TEXT,&#92;&#92;n  &#92;&#92;&#92;&quot;captured_at&#92;&#92;&#92;&quot; TEXT&#92;&#92;n)&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1ed8538c313cd812&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Query DLQ Records&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;98bd5b23672993a1&#92;&quot;,&#92;&quot;281734e9a00b621e&#92;&quot;,&#92;&quot;ad2553f403d14b2f&#92;&quot;],&#92;&quot;x&#92;&quot;:174,&#92;&quot;y&#92;&quot;:759,&#92;&quot;w&#92;&quot;:692,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;98bd5b23672993a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1ed8538c313cd812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Click to see DLQ records&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad2553f403d14b2f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;281734e9a00b621e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1ed8538c313cd812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad2553f403d14b2f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1ed8538c313cd812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Query DLQ Table&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;SELECT * FROM &#92;&#92;&#92;&quot;dlq&#92;&#92;&#92;&quot;;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;281734e9a00b621e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;DLQ Implementation&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;8e0ac077e92630b1&#92;&quot;,&#92;&quot;d8871599d4c76ed6&#92;&quot;,&#92;&quot;aece3dfb5407b2be&#92;&quot;,&#92;&quot;ddbfd80ec3da0419&#92;&quot;,&#92;&quot;18976ac55bc49b95&#92;&quot;,&#92;&quot;086adbd104082fc6&#92;&quot;,&#92;&quot;e23ce8129b8aa06a&#92;&quot;,&#92;&quot;ffc30231275f6b15&#92;&quot;,&#92;&quot;92504ed47d1acc08&#92;&quot;,&#92;&quot;a6d2276f504fb649&#92;&quot;,&#92;&quot;c1df30e71498b75e&#92;&quot;,&#92;&quot;0e16cc1c80d8d28c&#92;&quot;],&#92;&quot;x&#92;&quot;:174,&#92;&quot;y&#92;&quot;:439,&#92;&quot;w&#92;&quot;:1652,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;8e0ac077e92630b1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;POST /ingest&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;POST&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;http://localhost:1880/ingest&#92;&quot;,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d8871599d4c76ed6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d8871599d4c76ed6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Check Response&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// restore retry state from protected property&#92;&#92;nmsg.retry = msg._retry;&#92;&#92;n&#92;&#92;nif (msg.statusCode !== 200) {&#92;&#92;n    msg.error = `API returned ${msg.statusCode}`;&#92;&#92;n    node.error(msg.error, msg);&#92;&#92;n    return null;&#92;&#92;n}&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1470,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aece3dfb5407b2be&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aece3dfb5407b2be&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Success&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:1660,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ddbfd80ec3da0419&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Catch Errors&#92;&quot;,&#92;&quot;scope&#92;&quot;:[&#92;&quot;8e0ac077e92630b1&#92;&quot;,&#92;&quot;d8871599d4c76ed6&#92;&quot;],&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;18976ac55bc49b95&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18976ac55bc49b95&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Normalize Error&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.retry = msg._retry;&#92;&#92;n&#92;&#92;nif (typeof msg.error === &#39;object&#39;) {&#92;&#92;n    msg.error = msg.error.message || JSON.stringify(msg.error);&#92;&#92;n}&#92;&#92;n&#92;&#92;nmsg.error = msg.error || &#39;Processing failed&#39;;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;086adbd104082fc6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;086adbd104082fc6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retry Manager&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const MAX_ATTEMPTS = msg.retry.maxAttempts || 5;&#92;&#92;nconst BASE_DELAY_MS = 1000;&#92;&#92;nconst MAX_DELAY_MS = 30000;&#92;&#92;n&#92;&#92;nmsg.retry.attempts += 1;&#92;&#92;nmsg.retry.lastError = msg.error || &#39;Unknown error&#39;;&#92;&#92;nmsg.retry.lastAttemptAt = new Date().toISOString();&#92;&#92;n&#92;&#92;n// keep _retry in sync&#92;&#92;nmsg._retry = msg.retry;&#92;&#92;n&#92;&#92;nif (msg.retry.attempts &amp;gt;= MAX_ATTEMPTS) {&#92;&#92;n    msg.retry.exhausted = true;&#92;&#92;n    msg.dlq = {&#92;&#92;n        reason: &#39;Max retries exceeded&#39;,&#92;&#92;n        attempts: msg.retry.attempts,&#92;&#92;n        lastError: msg.retry.lastError,&#92;&#92;n        deadAt: new Date().toISOString()&#92;&#92;n    };&#92;&#92;n    return [null, msg];&#92;&#92;n}&#92;&#92;n&#92;&#92;nconst exponential = BASE_DELAY_MS * Math.pow(2, msg.retry.attempts - 1);&#92;&#92;nconst jitter = Math.random() * 1000;&#92;&#92;nconst delay = Math.min(exponential + jitter, MAX_DELAY_MS);&#92;&#92;n&#92;&#92;nmsg.delay = Math.round(delay);&#92;&#92;n&#92;&#92;nnode.status({&#92;&#92;n    fill: &#39;yellow&#39;,&#92;&#92;n    shape: &#39;ring&#39;,&#92;&#92;n    text: `Retry ${msg.retry.attempts}/${MAX_ATTEMPTS} in ${Math.round(delay / 1000)}s`&#92;&#92;n});&#92;&#92;n&#92;&#92;nreturn [msg, null];&#92;&quot;,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e23ce8129b8aa06a&#92;&quot;],[&#92;&quot;92504ed47d1acc08&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e23ce8129b8aa06a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Backoff Delay&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;delayv&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ffc30231275f6b15&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ffc30231275f6b15&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Restore Payload&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;_originalPayload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8e0ac077e92630b1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;92504ed47d1acc08&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Build DLQ Params&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;_msgid&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry.topic&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$string(_originalPayload)&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.attempts&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry.attempts&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.last_error&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry.lastError&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.captured_at&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$now()&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;x&#92;&quot;:890,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0e16cc1c80d8d28c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a6d2276f504fb649&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;DLQ Record Saved&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:1690,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c1df30e71498b75e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 1&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;e0addcc09f36a025&#92;&quot;],&#92;&quot;x&#92;&quot;:945,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ffc30231275f6b15&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e16cc1c80d8d28c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;85c883f958a8248e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert DLQ Record&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;INSERT INTO &#92;&#92;&#92;&quot;dlq&#92;&#92;&#92;&quot; (&#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;topic&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;payload&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;attempts&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;last_error&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;captured_at&#92;&#92;&#92;&quot;)&#92;&#92;nVALUES ($id, $topic, $payload, $attempts, $last_error, $captured_at)&#92;&#92;nON CONFLICT (&#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot;) DO UPDATE SET&#92;&#92;n  &#92;&#92;&#92;&quot;attempts&#92;&#92;&#92;&quot; = EXCLUDED.&#92;&#92;&#92;&quot;attempts&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;last_error&#92;&#92;&#92;&quot; = EXCLUDED.&#92;&#92;&#92;&quot;last_error&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;captured_at&#92;&#92;&#92;&quot; = EXCLUDED.&#92;&#92;&#92;&quot;captured_at&#92;&#92;&#92;&quot;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1290,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a6d2276f504fb649&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7cf8d797670d4025&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulated API — Fails 80% of the Time&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;5bda1677a303bad5&#92;&quot;,&#92;&quot;16098f6123028007&#92;&quot;,&#92;&quot;87108585e5177d34&#92;&quot;],&#92;&quot;x&#92;&quot;:174,&#92;&quot;y&#92;&quot;:659,&#92;&quot;w&#92;&quot;:732,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;5bda1677a303bad5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7cf8d797670d4025&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;POST /ingest&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;/ingest&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;post&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;16098f6123028007&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;16098f6123028007&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7cf8d797670d4025&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Mock API 80% Fail&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const shouldFail = Math.random() &amp;lt; 0.8;&#92;&#92;n&#92;&#92;nif (shouldFail) {&#92;&#92;n    msg.statusCode = 503;&#92;&#92;n    msg.payload = { error: &#92;&#92;&#92;&quot;Service unavailable&#92;&#92;&#92;&quot;, status: 503 };&#92;&#92;n} else {&#92;&#92;n    msg.statusCode = 200;&#92;&#92;n    msg.payload = { success: true, status: 200 };&#92;&#92;n}&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;87108585e5177d34&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;87108585e5177d34&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7cf8d797670d4025&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send Response&#92;&quot;,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a23e7b96d9aa726e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulate Sensor Reading&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;dd1b1440e1bf6cd4&#92;&quot;,&#92;&quot;2a9285c099b974a4&#92;&quot;,&#92;&quot;e0addcc09f36a025&#92;&quot;],&#92;&quot;x&#92;&quot;:174,&#92;&quot;y&#92;&quot;:339,&#92;&quot;w&#92;&quot;:622,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;dd1b1440e1bf6cd4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a23e7b96d9aa726e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Every 5s&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2a9285c099b974a4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2a9285c099b974a4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a23e7b96d9aa726e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulate Reading&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.payload = {&#92;&#92;n    sensorId: &#39;sensor-001&#39;,&#92;&#92;n    temperature: +(Math.random() * 40 + 10).toFixed(2),&#92;&#92;n    unit: &#39;celsius&#39;,&#92;&#92;n    timestamp: new Date().toISOString()&#92;&#92;n};&#92;&#92;nmsg.topic = &#39;sensors/temperature&#39;;&#92;&#92;nmsg._originalPayload = RED.util.cloneMessage(msg.payload);&#92;&#92;n&#92;&#92;nif (!msg._retry) {&#92;&#92;n    msg._retry = {&#92;&#92;n        attempts: 0,&#92;&#92;n        maxAttempts: 5,&#92;&#92;n        lastError: null,&#92;&#92;n        originalTimestamp: new Date().toISOString(),&#92;&#92;n        topic: msg.topic&#92;&#92;n    };&#92;&#92;n}&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e0addcc09f36a025&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e0addcc09f36a025&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b413f96e006352db&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a23e7b96d9aa726e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;c1df30e71498b75e&#92;&quot;],&#92;&quot;x&#92;&quot;:755,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;10288c58ceddb722&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/nr-tables-nodes&#92;&quot;:&#92;&quot;0.2.1&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow256.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-256&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;closing-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/how-to-implement-dlq-and-retries/#closing-thoughts&quot;&gt;Closing Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every message your system drops was someone&#39;s data. A sensor reading that never made it. A transaction that silently disappeared. An event that the downstream system never knew existed. In most IIoT deployments these failures are invisible. No record, no alert, no way to recover what was lost.&lt;/p&gt;
&lt;p&gt;That is the problem this pattern solves.&lt;/p&gt;
&lt;p&gt;A Dead Letter Queue does not make your system more reliable. Reliability comes from good infrastructure, careful design, and redundancy. What a DLQ gives you is honesty. An honest record of every message that could not be delivered, with enough context to understand why, and enough structure to do something about it.&lt;/p&gt;
&lt;p&gt;You deploy it once and it works quietly in the background until the moment you need it.&lt;/p&gt;
&lt;p&gt;And you will need it. Not because your flows are poorly built, but because distributed systems fail. APIs go down. Networks drop. Services timeout at the worst possible moment. The question has never been whether that happens. It is whether you are ready when it does.&lt;/p&gt;
&lt;p&gt;Now you are.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/</id>
        <title>The Bus Factor Problem in Integration Systems</title>
        <summary>Your integration system works great. Does anyone else know how</summary>
        <updated>2026-03-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The bus factor is a simple idea. If one person leaves your team, how much breaks? If the answer is &amp;quot;a lot,&amp;quot; your bus factor is one. Most integration systems have a bus factor of one.&lt;/p&gt;
&lt;p&gt;It&#39;s not because teams are sloppy. Integration work just tends to accumulate in corners. Systems get built quickly to solve real problems, and the person who builds them naturally becomes the person who understands them. They know why the retry logic is set the way it is, why data gets reshaped at that particular step, why two systems connect the way they do. That knowledge rarely makes it into documentation because there&#39;s always something more urgent to work on.&lt;/p&gt;
&lt;p&gt;Time passes. The system keeps running. Nobody questions it. Then that person moves to another team, takes a two-week vacation, or just gets sick at the wrong moment, and suddenly a routine maintenance task turns into a two-day investigation.&lt;/p&gt;
&lt;p&gt;The problem isn&#39;t unique to integration systems, but it hits them harder. Integration logic lives between other systems, it&#39;s rarely the focus of code reviews, and it&#39;s usually the last thing anyone thinks to document. Knowledge concentrates fast and spreads slowly.&lt;/p&gt;
&lt;p&gt;The good news is it&#39;s a solvable problem. The first step is knowing you have it. Before you read further, take two minutes to assess where your team stands today.&lt;/p&gt;
&lt;iframe src=&quot;https://bus-factory-problem-dashboard.flowfuse.cloud/dashboard/bus-factory-calculator&quot; width=&quot;100%&quot; height=&quot;650px&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Now you know where you stand. The rest of this article explains how integration systems end up here, why documentation alone never fixes it, and what it actually takes to change it.&lt;/p&gt;
&lt;h2 id=&quot;why-integration-systems-are-especially-vulnerable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#why-integration-systems-are-especially-vulnerable&quot;&gt;Why Integration Systems Are Especially Vulnerable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most engineering work leaves a trail. Pull requests, code reviews, commit messages, test cases. Software teams have spent decades building habits and tooling that make their work legible to others. Integration work tends to skip all of that.&lt;/p&gt;
&lt;p&gt;A flow gets built by one person to solve a specific problem: connect a PLC to a database, route sensor data to a dashboard, translate one protocol into another. It works, it gets deployed, and then it runs quietly in the background while everyone moves on. The person who built it moves on too, to the next urgent problem, the next system, the next deadline.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Illustration of an integration flow acting as a black box between PLCs, databases, and dashboards, highlighting that knowledge about the connections is concentrated in a single person.&quot; alt=&quot;&amp;quot;Illustration of an integration flow acting as a black box between PLCs, databases, and dashboards, highlighting that knowledge about the connections is concentrated in a single person.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integration-systems-black-box.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The people doing this work aren&#39;t cutting corners. They&#39;re IT engineers, automation specialists, OT technicians, and process engineers working under real time pressure. Their job is to get systems talking, not to produce documentation for a future colleague they&#39;ve never met. In most organizations, nobody has ever defined what good engineering practice looks like for integration work, so the default is to ship and move on.&lt;/p&gt;
&lt;p&gt;There&#39;s a structural problem compounding this. Integration flows don&#39;t belong cleanly to any one team. They&#39;re not part of the application codebase. They&#39;re not clearly IT&#39;s responsibility or OT&#39;s. They live in their own runtime, often on edge devices or gateways distributed across a facility, and they connect systems that different teams own. Nobody has obvious ownership, so nobody feels obvious accountability for making the knowledge transferable.&lt;/p&gt;
&lt;p&gt;The result is a system that works fine as long as the right person is available. The moment they&#39;re not, you find out just how much was living only in their head.&lt;/p&gt;
&lt;h2 id=&quot;what-happens-when-the-knowledge-walks-out-the-door&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#what-happens-when-the-knowledge-walks-out-the-door&quot;&gt;What Happens When the Knowledge Walks Out the Door&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The immediate impact is visible: something breaks and nobody knows how to fix it. But the slower damage is harder to measure.&lt;/p&gt;
&lt;p&gt;Teams start treating their own integration flows as black boxes. They&#39;re afraid to touch them because they don&#39;t understand them well enough to know what will break. New team members spend weeks or months just trying to figure out what exists and what it does. Simple changes take longer than they should because every modification requires archaeology first.&lt;/p&gt;
&lt;p&gt;Over time, organizations start building new flows around existing ones instead of modifying them, because modifying them feels risky. The system gets more complex. More people build more flows that only they understand. The bus factor gets worse, not better.&lt;/p&gt;
&lt;p&gt;In manufacturing environments, this isn&#39;t just a productivity problem. Integration flows connect real machines, real production lines, and real safety systems. A flow that nobody understands is a flow that nobody can safely change, debug, or improve. That&#39;s a real operational risk, and it compounds with scale.&lt;/p&gt;
&lt;h2 id=&quot;the-documentation-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#the-documentation-problem&quot;&gt;The Documentation Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The obvious answer is: write better documentation. And yes, that&#39;s true. But saying &amp;quot;just document it&amp;quot; has never actually solved the problem, and it&#39;s worth understanding why.&lt;/p&gt;
&lt;p&gt;Documentation is a separate task. That&#39;s the core issue. When an engineer finishes building a flow, the work feels done. The flow works. Sitting down to document it means context-switching into a different mode of thinking, opening a different tool, and writing for an audience that doesn&#39;t exist yet. Most of the time, that just doesn&#39;t happen.&lt;/p&gt;
&lt;p&gt;Even when documentation does exist, it goes stale. A flow gets modified. The documentation doesn&#39;t. Six months later, the documentation describes something that no longer exists, which is sometimes worse than no documentation at all.&lt;/p&gt;
&lt;p&gt;The teams that actually maintain good documentation tend to do it because it&#39;s built into how they work, not because they decided to be more disciplined. The process makes it easy and the tooling keeps it close to the work.&lt;/p&gt;
&lt;h2 id=&quot;how-flowfuse-approaches-the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#how-flowfuse-approaches-the-problem&quot;&gt;How FlowFuse Approaches the Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is an industrial data platform built on &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt;. It&#39;s designed for teams who need to connect machines, systems, and data across IT and OT environments at scale, with the governance and reliability that production environments require.&lt;/p&gt;
&lt;p&gt;What makes it relevant to the bus factor problem is where FlowFuse has chosen to put the intelligence.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;FlowFuse Expert&lt;/a&gt; is an AI assistant built directly into the Node-RED editor inside FlowFuse. It is not a generic AI. It is specifically trained on FlowFuse&#39;s own documentation, blog posts, and resources, which means it understands the platform, its nodes, and the industrial context it operates in. When you ask it a question, you are not talking to a general-purpose chatbot - you are talking to something that knows what a Function node is, what an MQTT broker does, and what your specific flow is actually doing.&lt;/p&gt;
&lt;p&gt;That last part matters. FlowFuse Expert can take your flow as context. Select a flow, add it to the conversation, and ask plain-language questions about it - what does this flow do, why is this node outputting a number instead of a string, where could this logic fail. It can also take your palette as context, so it knows which nodes you actually have installed and can give advice based on what is available to you rather than what exists in theory.&lt;/p&gt;
&lt;p&gt;For a team inheriting flows they didn&#39;t build, this changes the equation significantly. Instead of spending days reverse-engineering what a flow does, a new team member can get a working explanation in seconds and ask follow-up questions in plain language.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;YRc1DwkghRs&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/03/images/ff-expert-explaining-flow.jpeg&#39;); background-size: cover; background-position: center;&quot; title=&quot;FlowFuse Expert Explaining Selected Flow&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;The video above shows just one example - asking questions about a selected flow. FlowFuse Expert goes much further than that. You can query your live operational data through MCP tools in Insights mode, get inline code completions as you type inside Function nodes, generate CSS and HTML for FlowFuse Dashboard templates, build Function nodes from plain-language descriptions, and get intelligent suggestions for which node to add next. The more you use it, the less the work depends on any single person remembering how something was built.&lt;/p&gt;
&lt;p&gt;Beyond the chat interface, FlowFuse Expert also brings AI directly into Node-RED through Node-RED Embedded AI. This is AI that works where you already are - inside node editors and on the canvas - without needing to open a separate panel. It can write Function node code from a plain-language description, generate CSS and HTML for FlowFuse Dashboard templates, suggest which node to add next in a flow, and produce realistic test data to validate logic. It handles the JavaScript, the regex, the CSS, the JSON - so engineers can focus on the domain knowledge that actually requires a human.&lt;/p&gt;
&lt;h2 id=&quot;reducing-the-bus-factor-in-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#reducing-the-bus-factor-in-practice&quot;&gt;Reducing the Bus Factor in Practice&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Expert is one piece of a broader approach FlowFuse takes to making integration knowledge more durable.&lt;/p&gt;
&lt;p&gt;The platform includes version control for flows, so changes are tracked and teams can roll back when something goes wrong without needing to call the person who made the change. It supports team collaboration on a single Node-RED instance, which means flows don&#39;t have to be the work of one person in isolation. DevOps pipelines let teams move flows through development, staging, and production environments with proper governance rather than deploying directly to production from someone&#39;s laptop.&lt;/p&gt;
&lt;p&gt;Put together, these features don&#39;t just reduce the bus factor. They change the conditions that create it. When flows are version-controlled, when multiple people work on them together, when an AI can explain them on demand, the concentration of knowledge in one person&#39;s head becomes much harder to sustain accidentally.&lt;/p&gt;
&lt;p&gt;The bus factor never fully goes away. Key people will always carry important knowledge. But there&#39;s a meaningful difference between a team where one person is the only one who understands something, and a team where one person understands it best but the system can explain itself well enough that others can follow, contribute, and take over.&lt;/p&gt;
&lt;p&gt;The goal isn&#39;t to make everyone interchangeable. It&#39;s to make sure that when someone is out, the work can continue.&lt;/p&gt;
&lt;h2 id=&quot;closing-thought&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/03/bus-factory-problem-in-manufacturing/#closing-thought&quot;&gt;Closing Thought&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integration systems are the connective tissue of industrial operations. When they&#39;re well understood and well documented, they&#39;re an asset. When they&#39;re opaque and person-dependent, they&#39;re a liability that just hasn&#39;t failed yet.&lt;/p&gt;
&lt;p&gt;The bus factor problem doesn&#39;t go away on its own. Knowledge concentrates by default, distributing it requires the right conditions, the right process, and tooling that makes the good behavior easier than the bad. That&#39;s exactly what FlowFuse is built to do.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/edge-ai-is-80-percent-pipeline-and-20-percent-ai/</id>
        <title>Edge AI Is 80% Plumbing, 20% Intelligence</title>
        <summary>Why your Edge AI pilot is still a pilot.</summary>
        <updated>2026-02-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/edge-ai-is-80-percent-pipeline-and-20-percent-ai/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The model is the easy part. I know that is not what you were told. But it is true, and somewhere between your third deployment and your first production fire, you will stop arguing with it.&lt;/p&gt;
&lt;p&gt;Edge AI is infrastructure work. Unglamorous, load-bearing, invisible-until-it-breaks infrastructure work with a neural network sitting on top of it like a trophy on a foundation nobody inspected. The 20% is the trophy. The 80% is everything underneath it.&lt;/p&gt;
&lt;p&gt;Most Edge AI projects do not fail because the model was wrong. They fail because nobody budgeted for the plumbing, nobody respected the plumbing, and everybody assumed the plumbing would figure itself out.&lt;/p&gt;
&lt;p&gt;It does not figure itself out.&lt;/p&gt;
&lt;p&gt;Here is what I have watched happen, repeatedly, across manufacturing facilities that were serious about Edge AI, staffed it well, and still could not get past the pilot: the model worked. The demo worked. The business case was real. And then the project stalled. Not because the technology failed, but because the infrastructure the technology needed to survive in an actual plant was never built.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mckinsey.com/capabilities/people-and-organizational-performance/our-insights/the-organization-blog/avoid-pilot-purgatory-in-7-steps&quot;&gt;McKinsey put a number on this: 84% of manufacturers pursuing IIoT were stuck in pilot mode&lt;/a&gt;. More than a quarter for over two years. In the years since, the models have gotten better, the hardware has gotten cheaper, and the percentage has not moved. That tells you the model was never the constraint.&lt;/p&gt;
&lt;p&gt;What is the constraint? Data your system can actually trust. Updates that reach hardware you cannot physically touch. Security that was designed in, not bolted on. Monitoring that catches a drifting model before it causes a quality escape. And an operating model that answers, before something breaks at 3 a.m., who owns this: IT or OT.&lt;/p&gt;
&lt;p&gt;None of that is in the vendor&#39;s proposal. All of it determines whether the vendor&#39;s proposal is worth anything.&lt;/p&gt;
&lt;p&gt;The factory your AI vendor designed their solution for has clean data, modern equipment, stable connectivity, and IT and OT teams working from a shared operating model. That factory is a useful abstraction. It is not your plant.&lt;/p&gt;
&lt;p&gt;Your plant has PLCs from three different vendors. A historian configured in 2009 that your OT team will not let anyone touch because the last time someone touched it, production stopped for four hours. Legacy equipment on the shop floor with no digital interface, because when it was commissioned, &amp;quot;digital interface&amp;quot; was not a specification category that existed. Sensor data in proprietary formats. Timestamps that do not align across systems. Protocols that your IT team has never heard of and your OT team has been working around for a decade.&lt;/p&gt;
&lt;p&gt;Before a single inference runs at the edge, someone has to collect and normalize data from all of that. Protocol translation. Context tagging. Historian integration. That work is months of engineering. It is almost never scoped. And when it surfaces, it is always described as a surprise, even though everyone in the plant knew it was there.&lt;/p&gt;
&lt;p&gt;This is why &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; matters in manufacturing in a way that nothing else quite does. It was built for exactly this problem: connecting things that were never designed to talk to each other. Modbus, OPC-UA, Siemens S7, MQTT. Thousands of community-built nodes covering the full reality of what is on the factory floor, not the idealized version. Your OT engineers, the people who actually understand the equipment, can build integration flows without waiting for scarce software developers. The domain knowledge that has been locked in people&#39;s heads for years can finally become logic that runs.&lt;/p&gt;
&lt;p&gt;But Node-RED alone is a development tool. Running it in production, across a fleet of edge devices in multiple facilities, is a different problem entirely. And that gap, between a working flow on one machine and a reliable, managed, auditable deployment across your entire operation, is precisely where most IIoT projects quietly fall apart.&lt;/p&gt;
&lt;p&gt;FlowFuse was built to close that gap. Both gaps, actually. Because the problem in manufacturing is not just that the infrastructure is hard. It is that building the intelligence on top of it is also harder than the demos suggest, and most teams are doing both with the wrong tools.&lt;/p&gt;
&lt;p&gt;The OT engineer who has spent fifteen years learning one plant&#39;s quirks is not going to become a software developer. That was never a realistic ask. But they understand the equipment better than anyone who might be hired to build integrations for it, and if the tooling respects that knowledge, they can do the integration work themselves. Node-RED was the first tool in this space that actually respected that. Not because it simplified the problem, but because it let domain expertise drive the solution.&lt;/p&gt;
&lt;p&gt;FlowFuse starts from that same premise and takes it further, into the territory Node-RED was never designed to handle alone.&lt;/p&gt;
&lt;p&gt;Take what happens when you want to put a model in production. You have a data scientist who trained something useful — a predictive maintenance model, an anomaly detector, a vision system for defect classification. The model is accurate. It works on their laptop. And then there is the question of where it actually lives, how OT can interact with it, what happens when it needs to be retrained, and who owns it when something goes wrong at 2 a.m. on a Saturday.&lt;/p&gt;
&lt;p&gt;In most deployments, nobody has a good answer to any of those questions. The model ends up in a container somewhere that only the data scientist understands, connected to the plant by a fragile handshake that no one wants to touch. The OT team treats it like a black box because it is a black box.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/ai/onxx/&quot;&gt;FlowFuse&#39;s ONNX nodes&lt;/a&gt; change that by putting the model where OT engineers already work. You train, you export, you deploy it as a node in a flow — alongside the Modbus reads, the historian writes, the MQTT publishes. The inference runs locally, on the edge device, no cloud round trip, no latency the line cannot afford. When we &lt;a href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/&quot;&gt;deployed a motor anomaly detector this way&lt;/a&gt;, the thing that changed was not the model&#39;s accuracy. It was that the people running the line could see what the model was looking at, wire its output to the control logic themselves, and update it through the same pipeline they use for everything else. That is not a convenience improvement. That is the difference between a model that gets maintained and a model that gets abandoned.&lt;/p&gt;
&lt;p&gt;The same logic applies to the &lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;FlowFuse Expert&lt;/a&gt;. OT engineers are not waiting for JavaScript fluency. They know the equipment; they know what they need the flow to do; they just get slowed down in the translation between that knowledge and working code. The Expert handles the boilerplate — autocompletes flows, generates function node logic from a plain-language description, explains what a set of nodes does in terms that make sense. It is not a general-purpose chatbot bolted onto an IDE. It was trained on Node-RED and FlowFuse specifically, which means it gives answers that work in industrial contexts rather than answers that look plausible until you try to run them. For teams where the backlog of integration work is longer than the list of people who can do it, that matters.&lt;/p&gt;
&lt;p&gt;And then there is the part that breaks most programs before they get to ask any of these questions: operating at fleet scale.&lt;/p&gt;
&lt;p&gt;One Node-RED instance, on one machine, managed by the person who set it up, is survivable. Ten devices across two facilities, or a hundred devices across a global operation, is a different problem. You need to push an update to a device on a production line in a facility in another country, and you need to know it landed correctly, and you need to be able to roll it back in under five minutes if it did not. You need to prove, to an auditor or a regulator, exactly which software version was running on which device at which moment. You need to be sure that when a device is decommissioned, its credentials are gone and its configuration is immediately invalidated.&lt;/p&gt;
&lt;p&gt;None of that is possible with stock Node-RED. All of it is table stakes in a real manufacturing environment.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/&quot;&gt;snapshot-based&lt;/a&gt; deployments give you a tested, versioned, rollback-capable pipeline for every device in your fleet. &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;Staged rollouts&lt;/a&gt; let you push to a test group first, validate behavior in real conditions, and then promote to production — the same discipline software engineering spent twenty years learning, now available to the people managing industrial edge infrastructure. &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;Role-based access control&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/&quot;&gt;SSO integration&lt;/a&gt;, and a complete audit trail are in the architecture, not added later when someone asks for them. In automotive, pharmaceutical, and food manufacturing, where you need to prove exactly which software version was running on which device at which moment, that audit trail is not a reporting feature. It is compliance infrastructure.&lt;/p&gt;
&lt;p&gt;The manufacturers who escape pilot purgatory are not the ones with better models. They are the ones who decided, before the model was ever deployed, that the infrastructure was the product. The model is a feature. What makes the feature reliable, observable, and maintainable — across a fleet of heterogeneous devices, in real plants, over years — is everything underneath it.&lt;/p&gt;
&lt;p&gt;FlowFuse is that infrastructure. Not because it is the most technically sophisticated platform available, but because it was built for the actual factory floor: the PLCs from three vendors, the historian nobody wants to touch, the protocols IT has never heard of, the OT engineers who know more about this equipment than anyone who might be hired to replace them. It meets the plant where it is. That is a harder design constraint than building for the idealized version.&lt;/p&gt;
&lt;p&gt;The conference circuit will keep celebrating the 20%. The benchmark results, the accuracy curves, the inference speeds. That work matters. But it is not what separates the manufacturers generating real operational value from the ones still running the same pilot they started two years ago.&lt;/p&gt;
&lt;p&gt;What separates them is the plumbing.&lt;/p&gt;
&lt;p&gt;Build it on something that understands where you are starting from.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you are running Node-RED in production today, or trying to, FlowFuse is the operational layer that makes it scale. Device management, snapshot deployments, DevOps pipelines, ONNX-based AI inference, and the FlowFuse Expert to build faster, all built specifically for industrial environments. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start a 14-day free trial today&lt;/a&gt;. No abstractions. No greenfield assumptions. Just the infrastructure your plant actually needs.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/</id>
        <title>How to Build an MQTT-to-InfluxDB Data Pipeline (2026)</title>
        <summary>From MQTT broker to InfluxDB bucket, the right way.</summary>
        <updated>2026-02-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;An MQTT to InfluxDB is one of the most common and most critical pipelines in IIoT. Every timestamped telemetry event that drives decisions on the floor needs to land somewhere it can be queried, trended, and acted on.&lt;/p&gt;
&lt;p&gt;The typical approach is a custom Python script that subscribes to the broker, parses the payload, and writes to InfluxDB. It works until a sensor changes its payload format, or the script quietly dies over a weekend and nobody notices until Monday. Now you&#39;re debugging a process nobody else fully understands, with no visibility into what failed or when. Others stitch together multiple tools, each with its own config, its own failure modes, and its own logs to dig through at 2am. The complexity ends up hidden in places that are hard to see, hard to debug, and hard to hand off.&lt;/p&gt;
&lt;p&gt;This article takes a different approach. Using FlowFuse (the enterprise platform built on &lt;a href=&quot;https://flowfuse.com/&quot;&gt;Node-RED&lt;/a&gt;), you&#39;ll build the entire pipeline as a visual flow covering MQTT subscription, payload transformation, and InfluxDB write. Every step is visible, editable, and easy to hand off.&lt;/p&gt;
&lt;h2 id=&quot;tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#tl%3Bdr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What&lt;/strong&gt;: Build an MQTT-to-InfluxDB pipeline that subscribes to a broker, transforms the payload, and writes time-series data to InfluxDB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How&lt;/strong&gt;: Three nodes in FlowFuse: MQTT in, change node for transformation, and InfluxDB out. No custom scripts or glue code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why FlowFuse&lt;/strong&gt;: Every step is visual, editable, and easy to hand off. When something breaks, you know exactly where to look.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have the following in place.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A running FlowFuse instance. If you don&#39;t have one yet, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; to get started.&lt;/li&gt;
&lt;li&gt;An MQTT broker. FlowFuse Pro and Enterprise include a &lt;a href=&quot;https://flowfuse.com/docs/user/teambroker/&quot;&gt;built-in broker&lt;/a&gt;, and the &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mqtt/&quot;&gt;MQTT nodes&lt;/a&gt; configure themselves automatically. If you are using an external broker, keep your host, port, and credentials handy.&lt;/li&gt;
&lt;li&gt;A running InfluxDB instance, either local or on InfluxDB Cloud. Keep your URL, token, organization, and bucket name handy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-the-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#building-the-pipeline&quot;&gt;Building the Pipeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The flow has three stages. An MQTT in node subscribes to your broker and receives incoming sensor payloads. A change node transforms that payload into the structure InfluxDB expects. An InfluxDB out node takes that structured data and writes it to your bucket. That&#39;s the entire pipeline. Let&#39;s build it.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MQTT to InfluxDB architecture illustrating sensor data ingestion via MQTT, transformation in FlowFuse, and storage in an InfluxDB bucket&quot; alt=&quot;MQTT to InfluxDB architecture illustrating sensor data ingestion via MQTT, transformation in FlowFuse, and storage in an InfluxDB bucket&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-to--influxdb-architecture.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-install-the-influxdb-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#step-1%3A-install-the-influxdb-node&quot;&gt;Step 1: Install the InfluxDB Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED does not include an InfluxDB node out of the box, so you will need to install it first.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED editor in your FlowFuse instance.&lt;/li&gt;
&lt;li&gt;Click the main menu in the top right corner and select Manage Palette.&lt;/li&gt;
&lt;li&gt;Go to the Install tab and search for &lt;a href=&quot;https://flowfuse.com/integrations/node-red-contrib-influxdb/&quot;&gt;node-red-contrib-influxdb&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click Install. Once complete, the InfluxDB nodes will appear in your palette on the left side.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Node-RED editor palette displaying the InfluxDB nodes added via the node-red-contrib-influxdb package.&quot; alt=&quot;Node-RED editor palette displaying the InfluxDB nodes added via the node-red-contrib-influxdb package.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-configure-the-mqtt-in-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#step-2%3A-configure-the-mqtt-in-node&quot;&gt;Step 2: Configure the MQTT In Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Drag an MQTT in node onto the canvas and double-click it to open its settings. Click the pencil icon next to the Server field to add a new broker connection.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter your broker host in the Server field and set the Port.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;MQTT 3.1.1&lt;/code&gt; as the protocol version.&lt;/li&gt;
&lt;li&gt;Leave the Client ID blank to let Node-RED generate one automatically.&lt;/li&gt;
&lt;li&gt;The keepalive is 60 seconds by default, so there’s no need to change it.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;Automatically unsubscribe when disconnecting&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MQTT broker connection settings in Node-RED showing server, port, protocol version, and client ID fields.&quot; alt=&quot;MQTT broker connection settings in Node-RED showing server, port, protocol version, and client ID fields.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-in--config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Switch to the Security tab and enter your broker username and password.&lt;/li&gt;
&lt;li&gt;Click Add to save the broker configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MQTT broker security tab in Node-RED showing username and password fields.&quot; alt=&quot;MQTT broker security tab in Node-RED showing username and password fields.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-in--security.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you are on FlowFuse Pro or Enterprise, the built-in broker details will already be picked up by the node and you can skip the above.&lt;/p&gt;
&lt;p&gt;Once the broker is configured:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set the Topic to &lt;code&gt;acme-motors/detroit/welding/line-1/robot-3/temperature&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set QoS to 2 to minimize message loss and reduce duplicates between the broker and Node-RED. For true end-to-end de-duplication, add an idempotency strategy (for example, a unique key or timestamp handling) before writing to InfluxDB.&lt;/li&gt;
&lt;li&gt;Give the node the name &lt;code&gt;robot 3 temperature&lt;/code&gt; and click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MQTT in node configured in Node-RED with topic set to the ISA-95 hierarchy and QoS set to 2.&quot; alt=&quot;MQTT in node configured in Node-RED with topic set to the ISA-95 hierarchy and QoS set to 2.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt--in.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-transform-the-payload-with-a-change-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#step-3%3A-transform-the-payload-with-a-change-node&quot;&gt;Step 3: Transform the Payload with a Change Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When the MQTT in node receives a message, &lt;code&gt;msg.payload&lt;/code&gt; will look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-175&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-175&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1738830735000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;187.6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;temp-robot-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;normal&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-175&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The InfluxDB out node does not accept this structure directly. With &lt;code&gt;node-red-contrib-influxdb&lt;/code&gt;, the easiest pattern is to pass &lt;code&gt;msg.payload&lt;/code&gt; as an array, the first containing the fields to write and the second containing the tags. In InfluxDB, fields are the values you aggregate and query over, while tags are metadata used mainly for filtering and grouping. Getting this split right matters because you cannot aggregate or perform math on tags, only on fields.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a change node onto the canvas and connect it to the MQTT in node.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings and add the following rules:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.measurement&lt;/code&gt; to the string value &lt;code&gt;temperature&lt;/code&gt;. If your payload already contains the measurement name, you can set &lt;code&gt;msg.measurement&lt;/code&gt; dynamically from &lt;code&gt;msg.payload.measurement&lt;/code&gt; instead, making the flow reusable across multiple sensors without any changes. Otherwise, you can configure the measurement name directly in the InfluxDB out node.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the JSONata expression:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;     [{&amp;quot;value&amp;quot;: payload.value, &amp;quot;status&amp;quot;: payload.status, &amp;quot;time&amp;quot;: payload.timestamp}, {&amp;quot;sensor_id&amp;quot;: payload.sensor_id, &amp;quot;unit&amp;quot;: payload.unit}]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Give the node the name &lt;code&gt;transform for influxdb&lt;/code&gt; and click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Change node in Node-RED configured with rules to transform the MQTT payload into the InfluxDB structure.&quot; alt=&quot;Change node in Node-RED configured with rules to transform the MQTT payload into the InfluxDB structure.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-influxdb-influxdb-transform.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-configure-the-influxdb-out-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#step-4%3A-configure-the-influxdb-out-node&quot;&gt;Step 4: Configure the InfluxDB Out Node&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an InfluxDB out node onto the canvas and connect it to the change node.&lt;/li&gt;
&lt;li&gt;Double-click it to open its settings and click the pencil icon next to the Server field to add a new InfluxDB connection.
&lt;ul&gt;
&lt;li&gt;Set Version to &lt;code&gt;2.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter your InfluxDB instance URL.&lt;/li&gt;
&lt;li&gt;Enter your API token.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click Add to save the connection.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;InfluxDB server configuration in Node-RED showing version, URL, and API token fields.&quot; alt=&quot;InfluxDB server configuration in Node-RED showing version, URL, and API token fields.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb--config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Set the Organization to your organization name.&lt;/li&gt;
&lt;li&gt;Set the Bucket to the bucket you want to write data into.&lt;/li&gt;
&lt;li&gt;Leave the Measurement field blank since we are passing it via &lt;code&gt;msg.measurement&lt;/code&gt; from the change node. If you prefer to hardcode it, enter &lt;code&gt;temperature&lt;/code&gt; here.&lt;/li&gt;
&lt;li&gt;Give the node the name &lt;code&gt;write to influxdb&lt;/code&gt; and click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;InfluxDB out node configured in Node-RED with organization, bucket, and measurement fields.&quot; alt=&quot;InfluxDB out node configured in Node-RED with organization, bucket, and measurement fields.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-deploy-and-test&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#step-5%3A-deploy-and-test&quot;&gt;Step 5: Deploy and Test&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With all three nodes connected, click the Deploy button in the top right corner of the Node-RED editor. Once deployed, the flow will immediately start listening for messages on the topic you configured.&lt;/p&gt;
&lt;p&gt;As your sensor publishes readings, open your InfluxDB instance and navigate to Data Explorer. Select your bucket, filter by measurement, and run the query. You should see the values and tags coming in from the pipeline.&lt;/p&gt;
&lt;p&gt;If no data appears, open the Node-RED debug panel and check for any error messages on the InfluxDB out node. The most common issues are an incorrect API token, a mismatched organization name, or a bucket that does not exist yet in InfluxDB.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-influxdb-tutorial/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most MQTT-to-InfluxDB pipelines don&#39;t fail because the technology is wrong. They fail because the implementation is invisible: a script running somewhere, maintained by someone, that nobody else fully understands until it stops working.&lt;/p&gt;
&lt;p&gt;What you&#39;ve built here flips that. Three nodes, one canvas, zero ambiguity about where data comes from, how it&#39;s shaped, and where it lands. When something breaks, and in IIoT, something always eventually breaks, you&#39;re not grepping through logs or reverse-engineering a process. You&#39;re looking at a flow that tells you exactly what happened and where.&lt;/p&gt;
&lt;p&gt;From here, the pipeline is yours to grow. Handle multiple sensors by parameterizing the topic and measurement. Add a catch node so malformed payloads get logged instead of silently dropped. Connect your InfluxDB bucket to a FlowFuse dashboard and put live telemetry on the floor where operators can actually see it.&lt;/p&gt;
&lt;p&gt;The three nodes you deployed today are the foundation. Everything else is just adding to what&#39;s already visible.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/</id>
        <title>Building an AI Vibration Anomaly Detector for Industrial Motors</title>
        <summary>Detect motor faults early using AI-driven vibration analysis and anomaly detection.</summary>
        <updated>2026-02-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Bearing wear, shaft misalignment, and imbalance don&#39;t appear overnight. They develop over days or weeks, leaving a clear trail in vibration data long before any audible or thermal symptoms emerge. By the time a technician hears grinding or feels heat, the window for low-cost intervention has already closed.&lt;/p&gt;
&lt;p&gt;The challenge isn&#39;t visibility: it&#39;s continuity. Manual spot-checks capture a fraction of developing faults, and only if the timing is lucky. What&#39;s needed is something that watches constantly, understands what normal looks like, and flags the moment something shifts.&lt;/p&gt;
&lt;p&gt;This guide walks through building exactly that: a custom AI model that learns the healthy vibration signature of your motor, detects deviations in real time, and integrates directly into Node-RED using FlowFuse with no separate ML infrastructure required.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;Fkv2x3Kv0lY&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/02/images/anomaly-detection.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Motor Anomaly Detection System Built Using FlowFuse&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#how-it-works&quot;&gt;How It Works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An accelerometer mounted on the motor captures vibration across three axes (X, Y, Z) and publishes batches of raw readings to an MQTT broker every half-second. A Node-RED flow subscribes to those readings, extracts 33 statistical features per batch (covering energy, peak forces, shape, and distribution across all three axes) and passes them to a trained autoencoder.&lt;/p&gt;
&lt;h3 id=&quot;why-an-autoencoder%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#why-an-autoencoder%3F&quot;&gt;Why an Autoencoder?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An &lt;a href=&quot;https://en.wikipedia.org/wiki/Autoencoder&quot;&gt;autoencoder&lt;/a&gt; is a neural network trained to compress its input and then reconstruct it. The architecture used here is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Input (33) → Dense (16) → Dense (8) → Dense (16) → Output (33)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bottleneck layer (8 nodes) forces the model to learn a compact representation of the input. When trained exclusively on healthy motor data, the model learns to reconstruct normal vibration patterns with very low error. When conditions change (a bearing begins to wear, alignment drifts, imbalance develops) the vibration signature shifts, reconstruction error rises, and the system flags an anomaly.&lt;/p&gt;
&lt;p&gt;This approach is well-suited to industrial use because you almost certainly have abundant examples of normal operation, but few or no labeled examples of specific fault modes. You don&#39;t need to know what failure looks like; you only need to define what normal looks like.&lt;/p&gt;
&lt;h2 id=&quot;building-the-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#building-the-system&quot;&gt;Building the System&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The implementation has three stages: setting up hardware to collect vibration data, training the autoencoder on normal operation, and deploying the trained model in Node-RED for real-time inference.&lt;/p&gt;
&lt;h2 id=&quot;part-1%3A-hardware-and-data-requirements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#part-1%3A-hardware-and-data-requirements&quot;&gt;Part 1: Hardware and Data Requirements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide assumes you already have a vibration sensor publishing batches of acceleration readings across X, Y, and Z axes at regular intervals. The examples were built using an ESP32 wired to an ADXL345 accelerometer. If your hardware differs, the rest of the steps remain unchanged as long as your sensor publishes the same payload format.&lt;/p&gt;
&lt;h3 id=&quot;expected-payload-format&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#expected-payload-format&quot;&gt;Expected Payload Format&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each MQTT message contains a half-second snapshot of motor vibration. The sensor captures 256 measurements per axis and packages them into a single JSON payload:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-49&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-49&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;motor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;motor-01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1718000000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.04&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.04&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.03&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.98&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.97&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.96&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-49&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;At 500 Hz sampling, 256 values represent roughly half a second of continuous vibration. This batching approach matters because it gives the AI model enough context to detect patterns: a single data point is meaningless, but 256 points reveal the behavioral signature of how the motor is actually running.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;motor_id&lt;/code&gt; and &lt;code&gt;ts&lt;/code&gt; fields are ignored by the model and can be omitted or renamed without effect.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If your sensor uses different settings:&lt;/strong&gt; The feature extraction math works regardless of sample count or sampling rate. If your sensor samples at 200 Hz and sends 128 values per batch, each window represents 640 ms instead of 500 ms; the model doesn&#39;t care about absolute timing, only the shape of the vibration signature. Aim for at least 100–200 ms of data per window; anything shorter may not carry enough signal for reliable detection.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#mqtt-broker&quot;&gt;MQTT Broker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You&#39;ll need an MQTT broker to route messages between the sensor, the training script, and Node-RED. Make sure your sensor is publishing to a consistent topic so all three can stay in sync.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you&#39;re using &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; for enterprise Node-RED, a built-in MQTT broker is available on &lt;strong&gt;Pro&lt;/strong&gt; and &lt;strong&gt;Enterprise&lt;/strong&gt; tiers with no external setup required. &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;part-2%3A-training-the-autoencoder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#part-2%3A-training-the-autoencoder&quot;&gt;Part 2: Training the Autoencoder&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before deploying anything in Node-RED, you need a trained model that understands what normal motor vibration looks like. This is done with a single Python script that connects to your MQTT broker, collects vibration data while the motor runs normally, then automatically trains and exports the model when you&#39;re done.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;System requirements:&lt;/strong&gt; Python 3.11 or later. The steps below were tested on macOS (Apple Silicon); adapt as needed for Linux or Windows.&lt;/p&gt;
&lt;p&gt;Create and activate a virtual environment:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-87&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-87&quot; class=&quot;language-bash&quot;&gt;python3 &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; venv venv&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; venv/bin/activate&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-87&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Windows:&lt;/strong&gt; Replace &lt;code&gt;source venv/bin/activate&lt;/code&gt; with &lt;code&gt;venv&#92;Scripts&#92;activate&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Install dependencies:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-96&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-96&quot; class=&quot;language-bash&quot;&gt;pip3 &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; numpy paho-mqtt torch onnx onnxruntime scikit-learn&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-96&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#configuration&quot;&gt;Configuration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All setup lives in a single configuration block at the top of the script. Before running, update these variables to match your environment:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BROKER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hostname or IP of your MQTT broker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1883&lt;/code&gt; for plain MQTT, &lt;code&gt;8883&lt;/code&gt; for TLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USERNAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Broker username. Leave empty &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; if not required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PASSWORD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Broker password. Leave empty &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; if not required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLIENT_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any unique string identifying this client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TOPIC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The MQTT topic your sensor publishes to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MIN_WINDOWS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minimum samples to collect before training (default: 300)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MIN_STD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minimum standard deviation floor that prevents near-constant features from skewing normalisation (default: 0.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLIP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hard clamp applied after normalisation to prevent extreme values (default: 5.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EPOCHS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of training epochs (default: 200)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LEARNING_RATE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adam optimizer learning rate (default: 0.001)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;THRESHOLD_SIGMA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multiplier for threshold calculation: &lt;code&gt;mean + N × std&lt;/code&gt; of training errors (default: 3)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Threshold tuning:&lt;/strong&gt; The default &lt;code&gt;mean + 3σ&lt;/code&gt; threshold is a solid starting point, but every motor environment is different. If you see too many false positives during normal operation, increase &lt;code&gt;THRESHOLD_SIGMA&lt;/code&gt;. If faults are being missed, decrease it. You can also edit &lt;code&gt;threshold.json&lt;/code&gt; directly after training without rerunning the script.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;collect-and-train&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#collect-and-train&quot;&gt;Collect and Train&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a file called &lt;code&gt;train_model.py&lt;/code&gt; and paste the following. &lt;strong&gt;Start the motor first, then run the script.&lt;/strong&gt; The model needs to learn what running vibration looks like. Collecting data with the motor stopped or barely loaded will produce a model that treats idle conditions as normal and misses real anomalies.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-224&quot;&gt;
  &lt;pre class=&quot;language-python&quot;&gt;&lt;code id=&quot;code-224&quot; class=&quot;language-python&quot;&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;&lt;br /&gt;Motor Vibration Anomaly Detection: Data Collection and Training&lt;br /&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; json&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; signal&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; sys&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; numpy &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; np&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torch&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nn &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; nn&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; onnx&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; onnxruntime &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ort&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; onnx &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; numpy_helper&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TensorProto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; helper&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; paho&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mqtt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; mqtt&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; paho&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mqtt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; CallbackAPIVersion&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# ── Configuration ────────────────────────────────────────────────────────────&lt;/span&gt;&lt;br /&gt;BROKER         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;broker.example.com&quot;&lt;/span&gt;            &lt;span class=&quot;token comment&quot;&gt;# Your MQTT broker address or IP&lt;/span&gt;&lt;br /&gt;PORT           &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1883&lt;/span&gt;                            &lt;span class=&quot;token comment&quot;&gt;# 1883 for plain MQTT, 8883 for TLS&lt;/span&gt;&lt;br /&gt;USERNAME       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;                              &lt;span class=&quot;token comment&quot;&gt;# Leave as &quot;&quot; if broker has no auth&lt;/span&gt;&lt;br /&gt;PASSWORD       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;                              &lt;span class=&quot;token comment&quot;&gt;# Leave as &quot;&quot; if broker has no auth&lt;/span&gt;&lt;br /&gt;CLIENT_ID      &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;motor-trainer-01&quot;&lt;/span&gt;             &lt;span class=&quot;token comment&quot;&gt;# Any unique string for this client&lt;/span&gt;&lt;br /&gt;TOPIC          &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;factory/motor-01/vibration/raw&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Must match your sensor&#39;s publish topic&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# ── Training parameters ───────────────────────────────────────────────────────&lt;/span&gt;&lt;br /&gt;MIN_WINDOWS    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# Minimum samples before training is allowed&lt;/span&gt;&lt;br /&gt;MIN_STD        &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# Prevents near-constant features from exploding normalisation&lt;/span&gt;&lt;br /&gt;CLIP           &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5.0&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# Hard clip applied after normalisation&lt;/span&gt;&lt;br /&gt;EPOCHS         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# Number of training epochs&lt;/span&gt;&lt;br /&gt;LEARNING_RATE  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-3&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# Adam optimiser learning rate&lt;/span&gt;&lt;br /&gt;THRESHOLD_SIGMA &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;# Threshold = mean + N * std of training reconstruction errors&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# ─────────────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;training_data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;stop_flag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extract_features&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Extract 11 time-domain features from a signal array.&quot;&quot;&quot;&lt;/span&gt;&lt;br /&gt;    sig  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;asarray&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    mean &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    std  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;std&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    rms              &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sqrt&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    peak             &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    peak_to_peak     &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    crest_factor     &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rms &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    variance         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    std_dev          &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;std&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    skewness         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    kurtosis         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;br /&gt;    mean_abs         &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;br /&gt;    shape_factor     &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rms &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; mean_abs&lt;br /&gt;    impulse_factor   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; mean_abs&lt;br /&gt;    mean_sqrt_abs    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sqrt&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    clearance_factor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mean_sqrt_abs &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;rms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; peak&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; peak_to_peak&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; crest_factor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; variance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            std_dev&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; skewness&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kurtosis&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shape_factor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            impulse_factor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clearance_factor&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;featurize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Concatenate features from X, Y, Z → 33-element vector.&quot;&quot;&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;extract_features&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;            extract_features&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;            extract_features&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;on_connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userdata&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason_code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; properties&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; reason_code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Connected to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;BROKER&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subscribe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TOPIC&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Subscribed to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;TOPIC&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Run motor normally. Press Ctrl+C when done collecting.&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Connection failed: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;reason_code&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;on_message&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userdata&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; stop_flag&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loads&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        training_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;featurize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;training_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Collected &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; windows&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&#92;nError parsing message: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;train_and_export&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    N &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&#92;n&#92;nCollected &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;training_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; windows. Starting training...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    X &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;training_data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Normalisation with minimum std floor&lt;/span&gt;&lt;br /&gt;    mean &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; X&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;axis&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    std  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; X&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;std&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;axis&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    clamped &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; std &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; MIN_STD&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; clamped&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Clamping &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;clamped&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; near-constant features to std=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;MIN_STD&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        std&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;clamped&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MIN_STD&lt;br /&gt;&lt;br /&gt;    X_norm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clip&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;X &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;CLIP&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CLIP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Normalised range: [&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;X_norm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.3f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;X_norm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.3f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;]&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    scaler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mean&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tolist&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;std&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tolist&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;clip&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CLIP&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;scaler_params.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dump&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scaler&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; indent&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  Saved scaler_params.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Autoencoder definition&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Autoencoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Module&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token builtin&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__init__&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;encoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ReLU&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ReLU&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ReLU&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;forward&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decoder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;encoder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    model   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Autoencoder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    opt     &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;optim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Adam&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parameters&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lr&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;LEARNING_RATE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    loss_fn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MSELoss&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    data_t  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tensor&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;X_norm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dtype&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;train&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; epoch &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EPOCHS &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        opt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zero_grad&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        loss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; loss_fn&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data_t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data_t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        loss&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backward&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        opt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; epoch &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EPOCHS &lt;span class=&quot;token operator&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Epoch &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;epoch&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;EPOCHS&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;  loss=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;loss&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.6f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Calculate threshold&lt;/span&gt;&lt;br /&gt;    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;no_grad&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        recon  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data_t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        errors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recon &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; X_norm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; axis&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        thresh &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; THRESHOLD_SIGMA &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; errors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;std&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;threshold.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dump&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;threshold&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; thresh&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; indent&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Threshold (mean+&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;THRESHOLD_SIGMA&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;σ): &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;thresh&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.6f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  Saved threshold.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Export to ONNX&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Built manually to avoid version conflicts between PyTorch and ONNX exporters&lt;/span&gt;&lt;br /&gt;    layers   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;encoder.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;enc0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;encoder.2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;enc2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;decoder.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dec0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;decoder.2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dec2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    has_relu &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    inits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nodes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    cur &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;features&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prefix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; relu &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; has_relu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state_dict&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;prefix&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.weight&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;astype&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state_dict&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;prefix&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.bias&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;astype&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        inits &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;numpy_helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;from_array&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;w_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  numpy_helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;from_array&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;b_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        mm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;mm_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; add &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;add_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        nodes &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_node&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MatMul&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cur&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;w_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mm&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_node&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;b_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        cur &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; add&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; relu&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;relu_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            nodes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_node&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Relu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cur&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            cur &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&lt;br /&gt;&lt;br /&gt;    graph &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_graph&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        nodes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;autoencoder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_tensor_value_info&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;features&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TensorProto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FLOAT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_tensor_value_info&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cur&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TensorProto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FLOAT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        initializer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;inits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    proto &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;graph&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opset_imports&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;helper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;make_opsetid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    proto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ir_version &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;br /&gt;    onnx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;checker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;check_model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;proto&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    onnx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;save&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;proto&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;motor_autoencoder.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  Exported motor_autoencoder.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Sanity check&lt;/span&gt;&lt;br /&gt;    sess &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ort&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;InferenceSession&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;motor_autoencoder.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    out  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sess&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;features&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; X_norm&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;astype&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;float32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    mse  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;out &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; X_norm&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&#92;n  Sanity MSE (5 normal samples): &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;mse&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.6f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;  threshold: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;thresh&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.6f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; mse &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; thresh&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  ✓ Model correct , normal data scores below threshold.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  ⚠ Sanity MSE above threshold , collect more data and retrain.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;nDone. Copy these 3 files to your Node-RED server:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;  motor_autoencoder.onnx  scaler_params.json  threshold.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_sigint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sig&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; frame&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    stop_flag&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;training_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; MIN_WINDOWS&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&#92;n&#92;nNeed at least &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;MIN_WINDOWS&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; windows. Restart and collect longer.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    train_and_export&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;signal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;signal&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;signal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SIGINT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handle_sigint&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mqtt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Client&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback_api_version&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;CallbackAPIVersion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERSION2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                     client_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;CLIENT_ID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;username_pw_set&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;USERNAME&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PASSWORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;on_connect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; on_connect&lt;br /&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;on_message &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; on_message&lt;br /&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BROKER&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PORT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; keepalive&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loop_forever&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-224&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Let it collect for 5–10 minutes (aim for 300+ windows), then press &lt;strong&gt;Ctrl+C once&lt;/strong&gt; and wait. The script will train the model and export three files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;motor_autoencoder.onnx&lt;/code&gt; , the trained model in a portable, runtime-agnostic format&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scaler_params.json&lt;/code&gt; , the scaling parameters used to normalise input features&lt;/li&gt;
&lt;li&gt;&lt;code&gt;threshold.json&lt;/code&gt; , the reconstruction error value above which a reading is flagged as anomalous&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sanity check:&lt;/strong&gt; Watch the output at the end. &lt;code&gt;✓ Model correct&lt;/code&gt; means the model correctly scores normal data below the threshold. A warning means you should collect more data with the motor under its typical load and retrain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;when-to-retrain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#when-to-retrain&quot;&gt;When to Retrain&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The model captures what normal looks like at the time of training. Plan to retrain after any significant change to the motor&#39;s operating conditions: a maintenance overhaul, a change in load profile, a new mounting position, or seasonal temperature shifts that affect the vibration baseline. The process is identical, run the script again with the motor under its new normal conditions, replace the three output files, and restart the Node-RED flow.&lt;/p&gt;
&lt;h2 id=&quot;part-3%3A-deploying-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#part-3%3A-deploying-in-node-red&quot;&gt;Part 3: Deploying in Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The model now knows what healthy looks like. This section builds the Node-RED flow that runs continuously, scores every incoming vibration batch in real time, and raises an alert the moment something shifts.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-ai-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#installing-the-ai-nodes&quot;&gt;Installing the AI Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse provides a dedicated AI nodes package for Node-RED that includes ONNX runtime support.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These nodes are only available to FlowFuse users. If you don&#39;t have an account, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;get started here&lt;/a&gt; and follow the steps to &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;run the device agent&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED editor and go to &lt;strong&gt;Menu → Manage Palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;@flowfuse-nodes/nr-ai-nodes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you will see new nodes in the palette under the FlowFuse AI category. This guide uses the &lt;strong&gt;onnx&lt;/strong&gt; node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;FlowFuse AI nodes visible in the Node-RED palette under the FlowFuse AI category&quot; alt=&quot;FlowFuse AI nodes visible in the Node-RED palette under the FlowFuse AI category&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ai-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;loading-the-model-files&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#loading-the-model-files&quot;&gt;Loading the Model Files&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Place your three model files in the FlowFuse Device Agent directory before building the flow:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-302&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-302&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /opt/flowfuse-device/models&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; motor_autoencoder.onnx /opt/flowfuse-device/models/&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; scaler_params.json /opt/flowfuse-device/models/&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; threshold.json /opt/flowfuse-device/models/&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-302&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;building-the-inference-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#building-the-inference-flow&quot;&gt;Building the Inference Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The flow has five stages: receive the payload, extract features, scale and prepare, run inference, and score the result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Subscribe to MQTT&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add an &lt;strong&gt;mqtt-in&lt;/strong&gt; node and configure it to connect to the same broker and topic used during training. Set the output to auto-detect so the JSON payload is parsed automatically.&lt;/p&gt;
&lt;p&gt;If you are using the built-in FlowFuse MQTT broker, use the &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mqtt/&quot;&gt;FlowFuse MQTT nodes&lt;/a&gt; , these connect automatically when dragged into the flow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Extract Features&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add a &lt;strong&gt;function&lt;/strong&gt; node. In the &lt;strong&gt;Setup&lt;/strong&gt; tab, add the module &lt;code&gt;fs&lt;/code&gt;. Then paste the following into the &lt;strong&gt;On Message&lt;/strong&gt; tab:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-324&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-324&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractFeatures&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;sig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mean &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; std &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; absArr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;abs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;absArr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; meanAbs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; absArr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; meanSqrtAbs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; absArr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        rms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; peak&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rms &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; mean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        rms &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; meanAbs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; meanAbs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; peak &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;meanSqrtAbs &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1e-9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Scaler and threshold are cached in flow context after the first message.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// If you update the model files, restart the Node-RED flow to reload them.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;scaler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/opt/flowfuse-device/models/scaler_params.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; th &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/opt/flowfuse-device/models/threshold.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;scaler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;threshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; th&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;threshold&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; scaler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;scaler&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CLIP&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scaler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clip &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_STD&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; raw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extractFeatures&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extractFeatures&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extractFeatures&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; normalised &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scaler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;std&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MIN_STD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; scaler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mean&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CLIP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CLIP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Float32Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normalised&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;float32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;dims&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;threshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;threshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-324&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This function extracts 11 time-domain features per axis (33 total), loads the scaler on first run, and normalises the feature vector. The &lt;code&gt;MIN_STD&lt;/code&gt; floor and &lt;code&gt;±CLIP&lt;/code&gt; clamp mirror the values used during training and prevent near-constant features from producing extreme values, which are a common source of false positives with vibration sensors.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If you changed the model file path&lt;/strong&gt;, update the two &lt;code&gt;readFileSync&lt;/code&gt; paths to match your chosen directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;3. Run the Model&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add an &lt;strong&gt;onnx&lt;/strong&gt; node and configure it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model path:&lt;/strong&gt; &lt;code&gt;/opt/flowfuse-device/models/motor_autoencoder.onnx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input:&lt;/strong&gt; &lt;code&gt;msg.payload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The autoencoder compresses the 33-feature input through the bottleneck and reconstructs it on the output side. The reconstructed tensor is accessible in the next node via &lt;code&gt;msg.payload&lt;/code&gt;. Since the output key name depends on how the ONNX graph was exported, the scoring node retrieves it dynamically rather than relying on a hardcoded name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Score the Reconstruction Error&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add a second &lt;strong&gt;function&lt;/strong&gt; node:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-360&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-360&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;initialized&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;score_history&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;initialized&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Generic output key lookup — works regardless of tensor name&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; outputKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reconstructed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;outputKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cpuData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; threshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;threshold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reconstructed&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; history &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;score_history&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;score_history&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; history&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; smoothed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;anomaly_score &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; smoothed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;is_anomaly    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; smoothed &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; threshold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;severity      &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; smoothed &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; threshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;CRITICAL&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; smoothed &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; threshold &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;WARNING&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;NORMAL&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;anomaly_score&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; smoothed&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threshold&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;is_anomaly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;is_anomaly&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;severity &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-360&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This function computes mean squared error between the model&#39;s reconstruction and the normalised input, applies a 10-window rolling average to reduce sensitivity to transient spikes, then classifies the result as &lt;code&gt;NORMAL&lt;/code&gt;, &lt;code&gt;WARNING&lt;/code&gt;, or &lt;code&gt;CRITICAL&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Recovery time:&lt;/strong&gt; After an anomaly clears, the score returns to normal once the rolling window fills with healthy readings , typically 10 × your publish interval. At 500 ms publishing, that&#39;s roughly 5 seconds. Reduce the history window size for faster recovery; increase it to suppress false alarms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once deployed, the flow should look like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Completed Node-RED inference flow showing MQTT input, feature extraction function node, ONNX node, and anomaly scoring function node&quot; alt=&quot;Completed Node-RED inference flow showing MQTT input, feature extraction function node, ONNX node, and anomaly scoring function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Act on the Result&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Connect the scoring output to whatever suits your operation. For testing, a debug node shows results in real time. For production, an mqtt-out node can publish anomaly alerts downstream, the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; package can visualise the anomaly score over time with a clear motor state indicator, and alerting nodes can notify your team directly, via &lt;a href=&quot;https://flowfuse.com/node-red/notification/email/&quot;&gt;Telegram&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/node-red/notification/telegram/&quot;&gt;email&lt;/a&gt;, or &lt;a href=&quot;https://flowfuse.com/blueprints/other/mobile-alerting/&quot;&gt;SIGNL4&lt;/a&gt; for structured mobile alerts with on-call scheduling and acknowledgement tracking.&lt;/p&gt;
&lt;h3 id=&quot;what-the-output-looks-like&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#what-the-output-looks-like&quot;&gt;What the Output Looks Like&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each message produces a structured result:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-387&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-387&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;anomaly_score&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.842&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;threshold&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.703&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;is_anomaly&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;severity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WARNING&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-387&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;is_anomaly&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, the motor is behaving within the expected range. When it flips to &lt;code&gt;true&lt;/code&gt;, the vibration pattern has shifted beyond the acceptable boundary, giving you time to act before the problem becomes a failure. A severity of &lt;code&gt;CRITICAL&lt;/code&gt; means the score has crossed twice the threshold, signalling a more significant deviation that warrants immediate attention.&lt;/p&gt;
&lt;h2 id=&quot;what-this-system-won&#39;t-tell-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/motor-anomaly-detector-ai/#what-this-system-won&#39;t-tell-you&quot;&gt;What This System Won&#39;t Tell You&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This approach works well, but it&#39;s worth being clear about where it stops.&lt;/p&gt;
&lt;p&gt;The autoencoder learns a statistical boundary around the vibration patterns it was trained on. It doesn&#39;t understand physics, it doesn&#39;t know the difference between a worn bearing and a loose mounting bolt, and it has no concept of severity beyond the reconstruction error score. When it flags an anomaly, it&#39;s telling you that something has changed, not what changed or why. Diagnosing the root cause still requires a technician with domain knowledge.&lt;/p&gt;
&lt;p&gt;Training data quality matters more than model architecture. A model trained on data collected while the motor was lightly loaded, recently serviced, or running in cool ambient conditions will treat those as &amp;quot;normal.&amp;quot; If real operating conditions differ, the threshold may be poorly calibrated from day one, generating either chronic false positives or, worse, missing genuine faults. There&#39;s no substitute for collecting training data under representative, sustained, real-world load.&lt;/p&gt;
&lt;p&gt;False positives are inevitable in early deployment. External vibration from nearby equipment, transient load spikes, or sensor cable movement can all push the score above threshold momentarily. The rolling average window helps, but it doesn&#39;t eliminate them. Treat the first few weeks as a calibration period: log alerts, investigate them, and adjust &lt;code&gt;THRESHOLD_SIGMA&lt;/code&gt; or the window size based on what you learn. The system improves with attention.&lt;/p&gt;
&lt;p&gt;Finally, anomaly detection is an early warning layer, not a maintenance strategy on its own. It tells you to look sooner, not what to do when you get there. Pair it with regular physical inspection, lubrication schedules, and, where possible, a domain expert who can interpret the alerts in context. Used that way, it earns its place. Used as a replacement for those things, it will eventually let you down.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/</id>
        <title>Modbus TCP vs Modbus RTU: Reliability, Latency, and Failure Modes</title>
        <summary>What nobody tells you until the line goes down</summary>
        <updated>2026-02-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Modbus shipped in 1979. It has outlasted every protocol that was meant to replace it, survived the transition from relay logic to microprocessors and modern SCADA systems, and is still running production lines today. That kind of longevity does not happen by accident. It exists because the protocol is simple, deterministic, and unambiguous, at least in its original form, a point I have discussed in more detail in a &lt;a href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/&quot;&gt;separate article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then TCP came along. The data model stayed the same, identical function codes and identical register maps. But the assumptions underneath changed completely, including expectations about the network, failure modes, and what happens when things go wrong. The industry gained real capability, but it also inherited an entirely new class of problems, ones that look nothing like the challenges Modbus engineers spent forty-seven years learning to solve.&lt;/p&gt;
&lt;p&gt;That gap is what most people miss. And it is exactly what this post is about.&lt;/p&gt;
&lt;h2 id=&quot;they-are-not-the-same-protocol-in-different-clothes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#they-are-not-the-same-protocol-in-different-clothes&quot;&gt;They Are Not the Same Protocol in Different Clothes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus RTU runs over serial. That sounds simple until you consider what serial actually means in practice: one master, multiple slaves, one conversation at a time. The master initiates every transaction, the slave responds, and nothing else happens on the wire until that exchange completes.&lt;/p&gt;
&lt;p&gt;The physical layer is almost always RS-485 in industrial installations, a differential pair that can run hundreds of meters, tolerate significant electrical noise, and connect up to 247 devices on a single bus.&lt;/p&gt;
&lt;p&gt;That architecture imposes hard constraints. Only one device can transmit at a time. Timing between bytes within a frame matters: RTU uses silence on the line to mark frame boundaries, so a gap of 3.5 character times signals the end of one message and the start of the next. Get the baud rate wrong, introduce a noisy cable that stretches a byte, or misconfigure inter-character timing, and the frame parser loses its place. The message is silently discarded. No retransmission, no acknowledgment, just a timeout.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing Modbus RTU on RS-485 and Modbus TCP on Ethernet.&quot; alt=&quot;Image showing Modbus RTU on RS-485 and Modbus TCP on Ethernet.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-rtu-and-tcp-physical-layer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Modbus TCP moves the same application layer onto Ethernet and wraps it in a TCP socket. The serial constraints disappear. Multiple masters can coexist, transactions can be pipelined, and the physical layer handles collision detection and retransmission. What you gain in flexibility, you trade for a different set of assumptions. TCP guarantees delivery, but not timing. A retransmission storm on a busy network can stretch response times in ways that RTU, for all its limitations, never would.&lt;/p&gt;
&lt;h2 id=&quot;latency%3A-what-the-numbers-actually-mean-on-the-floor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#latency%3A-what-the-numbers-actually-mean-on-the-floor&quot;&gt;Latency: What the Numbers Actually Mean on the Floor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RTU latency is predictable almost to the microsecond. That sounds like a strength until you realize how slow predictable can be.&lt;/p&gt;
&lt;p&gt;At 9600 baud, a typical Modbus RTU transaction (request plus response) takes 50 to 100 milliseconds per device. Move to 115200 baud and that drops under 10 milliseconds. But you are still polling sequentially. Ten devices at 9600 baud means your slowest sensor gets updated once per second at best. Add more devices and the math gets worse in a straight line.&lt;/p&gt;
&lt;p&gt;That ceiling matters. A real-world example: a water treatment plant running 32 RTU devices on a single RS-485 bus at 9600 baud had a worst-case poll cycle of nearly four seconds. When the control engineer needed tighter feedback on a pH dosing loop, the only options were to reduce the device count on that segment, split the bus, or increase baud rate, all of which required physical work on a running system.&lt;/p&gt;
&lt;p&gt;Modbus TCP removes the baud rate ceiling and adds pipelining. A well-configured TCP master can have multiple transactions in flight simultaneously. On a lightly loaded Ethernet network, round trip times under 2 milliseconds are routine. For many applications, that is enough to stop thinking about latency altogether.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Chart comparing Modbus RTU polling latency with Modbus TCP network latency&quot; alt=&quot;Chart comparing Modbus RTU polling latency with Modbus TCP network latency&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-rtu-tcp-latency.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The catch is that Ethernet latency is not flat. It varies with network load, switch queue depth, and the TCP stack on the device side. Most of the time the numbers look excellent. Under the wrong conditions, they do not. A PLC with a modest embedded TCP stack, hit with traffic from a network scan or a broadcast storm, can stretch its response time by an order of magnitude. RTU would have delivered the same response time it always does.&lt;/p&gt;
&lt;p&gt;RTU offers better worst-case latency. TCP offers better average latency. In industrial control, worst-case is usually what you design for.&lt;/p&gt;
&lt;h2 id=&quot;failure-modes%3A-what-breaks%2C-how-it-breaks%2C-and-whether-you-will-know&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#failure-modes%3A-what-breaks%2C-how-it-breaks%2C-and-whether-you-will-know&quot;&gt;Failure Modes: What Breaks, How It Breaks, and Whether You Will Know&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where the two protocols diverge most sharply, and where choosing wrong costs the most.&lt;/p&gt;
&lt;h3 id=&quot;rtu-failures-are-loud-and-physical&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#rtu-failures-are-loud-and-physical&quot;&gt;RTU Failures Are Loud and Physical&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;RTU failures tend to be physical. A corroded terminal block. A cable run too close to a variable frequency drive. A termination resistor missing from one end of the bus. The symptoms are usually obvious: CRC errors climb, devices stop responding, the master logs timeouts.&lt;/p&gt;
&lt;p&gt;What RTU rarely does is fail silently. Framing errors and timeouts are visible. The master knows a transaction failed. The application layer gets a clear signal that something is wrong, even if locating the fault takes time.&lt;/p&gt;
&lt;p&gt;Locating it is the hard part. RS-485 is a shared medium, which means a single bad connection can drag down every device on the segment. Isolating which node is responsible requires methodical disconnection or a bus analyzer. Neither is fast at 2 AM with a line down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But at least you know it is down.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;tcp-failures-are-quiet-and-strange&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#tcp-failures-are-quiet-and-strange&quot;&gt;TCP Failures Are Quiet and Strange&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TCP failures are quieter and more varied. The physical layer is more robust: Ethernet cable is forgiving, switches regenerate signals, and a single bad port does not take down the network. But the failure surface is much broader.&lt;/p&gt;
&lt;p&gt;A device can be electrically healthy and passing traffic, yet still behave badly. Connection state gets out of sync. A TCP socket on a cheap embedded device does not close cleanly after a timeout, leaving the master waiting on a half-open connection that looks alive but delivers nothing. A managed switch renegotiating link speed during a firmware update introduces 30 seconds of elevated latency that looks, from the application&#39;s perspective, like a slow device.&lt;/p&gt;
&lt;p&gt;The worst TCP failures are the ones that are almost working. Partial connectivity. Occasional dropped transactions. Response times elevated but not elevated enough to trip a timeout threshold.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Half-open TCP socket failure where the master waits on a connection that never responds.&quot; alt=&quot;Half-open TCP socket failure where the master waits on a connection that never responds.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-tcp-open-connection-failure.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;RFC 793 formally defines the half-open state: when one end of a TCP connection crashes or closes without notifying the other, the remaining side may wait indefinitely on a connection that appears alive and delivers nothing (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc793&quot;&gt;RFC 793, Section 3.4&lt;/a&gt;). Rockwell Automation&#39;s troubleshooting documentation describes how conditions like duplex mismatches during switch replacement can produce exactly this pattern: performance that degrades quietly and stays within configured thresholds (&lt;a href=&quot;https://literature.rockwellautomation.com/idc/groups/literature/documents/at/enet-at003_-en-p.pdf&quot;&gt;Rockwell Automation, ENET-AT003&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;RTU tends to fall over cleanly. TCP tends to degrade quietly. Degraded is harder to catch than broken.&lt;/p&gt;
&lt;h3 id=&quot;tcp-introduces-a-failure-mode-that-rtu-never-had%3A-security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#tcp-introduces-a-failure-mode-that-rtu-never-had%3A-security&quot;&gt;TCP Introduces a Failure Mode That RTU Never Had: Security&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modbus has no authentication. On a serial bus, that is usually acceptable, because physical access to the wire implies physical access to the facility. On an Ethernet network, that assumption collapses entirely.&lt;/p&gt;
&lt;p&gt;Modbus TCP devices reachable from a corporate network, or worse from the internet, will respond to commands from anyone who sends them. No credentials. No audit trail. No way to distinguish a legitimate master from an attacker with a laptop and a Modbus client.&lt;/p&gt;
&lt;p&gt;This is not theoretical. Shodan regularly turns up Modbus TCP devices with publicly routable IP addresses. ICS security assessments routinely find Modbus exposed on flat networks shared with corporate IT. The clearest demonstration of what that exposure enables is &lt;a href=&quot;https://www.dragos.com/blog/protect-against-frostygoop-ics-malware-targeting-operational-technology/&quot;&gt;FrostyGoop&lt;/a&gt;, malware discovered by Dragos in 2024 and the first ever to use Modbus TCP to cause direct physical impact. Attackers targeted a district energy company in Lviv, Ukraine supplying heat to over 600 apartment buildings — port 502 was open to the internet, no network compromise required, and remediation took nearly two days while residents endured sub-zero temperatures. No credentials were needed. Modbus provided none to ask for.&lt;/p&gt;
&lt;p&gt;RTU is not inherently secure either, but attacking it requires being physically present on the wire. TCP removes that requirement entirely.&lt;/p&gt;
&lt;h2 id=&quot;choosing-between-them&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#choosing-between-them&quot;&gt;Choosing Between Them&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most engineers do not choose between RTU and TCP from a blank slate. They inherit a system, get handed a specification, or discover that the device they need only supports one of them. The real decision is narrower: whether what is already in place is appropriate for what the system now needs to do.&lt;/p&gt;
&lt;p&gt;RTU is the right answer when device count is small, cable runs are already there, polling rates are modest, and nothing outside the cabinet needs to reach the network. Those conditions describe a large percentage of working industrial installations. Changing a system that meets all of them adds risk for no operational benefit.&lt;/p&gt;
&lt;p&gt;TCP makes sense when you need to integrate field devices with higher-level systems like SCADA, historians, or MES, when device count or poll rate has grown beyond what serial can comfortably handle, or when the network already exists and adding serial infrastructure would cost more than it saves. It also makes sense when you need multiple masters, which serial cannot support without external arbitration hardware.&lt;/p&gt;
&lt;p&gt;The hybrid case is a serial network running reliably for fifteen years, with a gateway at the head end converting RTU to TCP for the SCADA system. It is more common than either pure scenario, and more sensible than it looks on paper. The gateway adds a failure point, but it also insulates field devices from the corporate network. That insulation is worth keeping. Replacing it to simplify the architecture is usually not the right trade.&lt;/p&gt;
&lt;h2 id=&quot;what-to-actually-do-differently-based-on-this&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/modbus-tcp-vs-modbus-rtu/#what-to-actually-do-differently-based-on-this&quot;&gt;What to Actually Do Differently Based on This&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are deploying RTU: use the highest baud rate the cable length and device count will reliably support, do not leave devices at 9600 baud out of habit; document your bus topology, because when something fails at night the person troubleshooting will not be you; and install proper termination resistors at both ends of every RS-485 segment, since this causes more problems than almost anything else.&lt;/p&gt;
&lt;p&gt;If you are deploying TCP: isolate Modbus devices on a dedicated VLAN or network segment and never put them on the corporate LAN; configure short TCP timeouts and explicit connection retry logic in your master, because half-open connections will happen; and log poll latency over time, since degradation that stays inside timeout thresholds will not alarm and you have to trend it.&lt;/p&gt;
&lt;p&gt;If you are maintaining a hybrid gateway architecture, resist the urge to rationalize it away. It is doing work.&lt;/p&gt;
&lt;p&gt;The two protocols make different guarantees, fail differently, and require different diagnostic skills when something goes wrong. Understanding that distinction before the system is designed costs nothing. Understanding it for the first time during an incident costs considerably more.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/getting-started-with-canbus/</id>
        <title>CAN Bus Tutorial: Connect to Dashboards, Cloud, and Industrial Systems</title>
        <summary>Build vehicle and industrial automation systems without low-level drivers or proprietary tools</summary>
        <updated>2026-02-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/getting-started-with-canbus/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;If you work with vehicles, industrial automation, or embedded systems, you&#39;ve likely encountered &lt;strong&gt;CAN bus&lt;/strong&gt;, the communication backbone that connects ECUs, sensors, controllers, and actuators in real-world environments. The challenge isn&#39;t just reading CAN data; it&#39;s getting that data into your dashboards, cloud platforms, databases, or industrial control systems.&lt;/p&gt;
&lt;p&gt;Traditionally, this meant dealing with vendor-specific drivers, proprietary gateway hardware, and low-level C code just to bridge CAN bus to modern IT infrastructure. &lt;strong&gt;SocketCAN&lt;/strong&gt; and &lt;strong&gt;FlowFuse&lt;/strong&gt; offer a better approach.&lt;/p&gt;
&lt;p&gt;SocketCAN brings CAN bus support directly into the Linux networking stack, treating CAN interfaces like Ethernet or Wi-Fi. Combined with FlowFuse&#39;s visual flow-based programming (built on Node-RED), you can connect CAN bus devices to virtually any system, building real-time dashboards, streaming data to cloud platforms, integrating with SCADA systems, or bridging to MQTT, databases, REST APIs, and industrial protocols, all without writing low-level code or relying on proprietary tools.&lt;/p&gt;
&lt;p&gt;In this tutorial, you&#39;ll set up SocketCAN on Linux, integrate it with FlowFuse, and learn how to send and receive CAN frames, establishing the foundation for connecting your CAN infrastructure to the broader industrial ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;understanding-can-bus&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#understanding-can-bus&quot;&gt;Understanding CAN Bus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CAN (Controller Area Network) is a robust communication protocol that allows multiple devices, such as sensors, controllers, and actuators, to share data over a two-wire bus. Commonly used in automotive, industrial, and embedded systems, CAN broadcasts all messages to every device on the network, with each message identified by an ID that devices use to filter relevant data.&lt;/p&gt;
&lt;h2 id=&quot;what-is-socketcan%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#what-is-socketcan%3F&quot;&gt;What Is SocketCAN?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SocketCAN is a Linux kernel feature that integrates CAN bus support directly into the networking stack. It exposes CAN hardware as standard network interfaces (like &lt;code&gt;can0&lt;/code&gt; or &lt;code&gt;vcan0&lt;/code&gt;), allowing you to configure and interact with CAN using familiar Linux networking commands. This abstraction means your application code remains the same whether you&#39;re using a USB-to-CAN adapter, an embedded controller, or a virtual interface, making development, testing, and hardware changes significantly simpler.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, you&#39;ll need a Linux environment where you can run FlowFuse and configure SocketCAN. In our setup, FlowFuse runs on an Ubuntu-based edge device, and we use a virtual CAN interface to simulate a real CAN bus. This allows you to complete the tutorial without any physical CAN hardware.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, ensure your environment meets the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Linux Operating System&lt;/strong&gt;
SocketCAN is a Linux kernel feature and requires a Linux-based system. This guide is tested on Ubuntu 20.04+ and other Debian-based distributions, though the same concepts apply to any modern Linux distribution with kernel 2.6.25 or later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Running FlowFuse Instance&lt;/strong&gt;
FlowFuse is built on top of Node-RED, providing the fastest and most production-ready way to deploy, manage, and govern your flow applications on edge devices. If you&#39;re using plain Node-RED, this tutorial will work there as well. For installation details of FlowFuse, see this &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;guide&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;System Permissions&lt;/strong&gt;
Root or sudo privileges are required to load kernel modules, create network interfaces, and configure SocketCAN devices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CAN Hardware or Virtual Interface&lt;/strong&gt;
This tutorial uses a &lt;strong&gt;virtual CAN (vcan)&lt;/strong&gt; interface to demonstrate SocketCAN and FlowFuse integration without requiring physical hardware.
In production deployments, physical CAN interfaces are typically used, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;USB-to-CAN adapters (for example, PEAK PCAN-USB or Kvaser devices)&lt;/li&gt;
&lt;li&gt;Embedded CAN controllers (such as MCP2515 via SPI)&lt;/li&gt;
&lt;li&gt;Built-in CAN interfaces on industrial computers or single-board computers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The FlowFuse flows and application logic remain the same when switching between virtual and physical CAN interfaces; only the underlying CAN interface configuration differs.&lt;/p&gt;
&lt;h3 id=&quot;enabling-can-interfaces-with-socketcan&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#enabling-can-interfaces-with-socketcan&quot;&gt;Enabling CAN Interfaces with SocketCAN&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before FlowFuse can interact with a CAN bus, a CAN network interface must be available and active at the operating system level. SocketCAN does not automatically create or enable interfaces; this step is always required, whether you are using a virtual or physical CAN bus.&lt;/p&gt;
&lt;p&gt;The setup differs slightly depending on your environment.&lt;/p&gt;
&lt;h4 id=&quot;option-a%3A-virtual-can-(vcan)-for-development-and-testing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#option-a%3A-virtual-can-(vcan)-for-development-and-testing&quot;&gt;Option A: Virtual CAN (vcan) for Development and Testing&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A virtual CAN interface allows CAN frames to be exchanged entirely in software. It is useful for development, testing, and learning, but it does not model physical bus timing or electrical behavior.&lt;/p&gt;
&lt;h5 id=&quot;enable-vcan-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#enable-vcan-support&quot;&gt;Enable vcan Support&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Load the virtual CAN kernel module:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-99&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-99&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; modprobe vcan&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-99&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Verify that it is loaded:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-103&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-103&quot; class=&quot;language-bash&quot;&gt;lsmod &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; vcan&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-103&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h5 id=&quot;create-and-enable-the-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#create-and-enable-the-interface&quot;&gt;Create and Enable the Interface&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Create a virtual CAN interface named &lt;code&gt;vcan0&lt;/code&gt;:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-110&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-110&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; dev vcan0 &lt;span class=&quot;token builtin class-name&quot;&gt;type&lt;/span&gt; vcan&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; up vcan0&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-110&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Verify the interface:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-114&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-114&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; show vcan0&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-114&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;At this point, &lt;code&gt;vcan0&lt;/code&gt; is ready to be used by SocketCAN applications such as FlowFuse.&lt;/p&gt;
&lt;h4 id=&quot;option-b%3A-physical-can-hardware-for-production-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#option-b%3A-physical-can-hardware-for-production-systems&quot;&gt;Option B: Physical CAN Hardware for Production Systems&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When using real CAN hardware, the interface is exposed by a hardware driver, but it still must be explicitly configured and enabled.&lt;/p&gt;
&lt;h5 id=&quot;1.-hardware-driver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#1.-hardware-driver&quot;&gt;1. Hardware Driver&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Most common CAN hardware is supported directly by the Linux kernel:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;USB-to-CAN adapters are typically detected automatically when connected&lt;/li&gt;
&lt;li&gt;SPI-based CAN controllers (for example, MCP2515) require kernel and device-tree configuration&lt;/li&gt;
&lt;li&gt;Built-in CAN controllers may require BIOS or kernel configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the driver is loaded, a CAN interface such as &lt;code&gt;can0&lt;/code&gt; becomes visible to the system.&lt;/p&gt;
&lt;h5 id=&quot;2.-configure-and-enable-the-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#2.-configure-and-enable-the-interface&quot;&gt;2. Configure and Enable the Interface&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Physical CAN interfaces must be configured with a bitrate before use:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-156&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-156&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; can0 up &lt;span class=&quot;token builtin class-name&quot;&gt;type&lt;/span&gt; can bitrate &lt;span class=&quot;token number&quot;&gt;500000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-156&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This command enables the CAN interface, sets the bus bitrate, and makes the interface available to SocketCAN applications.&lt;/p&gt;
&lt;h5 id=&quot;3.-verify-the-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#3.-verify-the-interface&quot;&gt;3. Verify the Interface&lt;/a&gt;&lt;/h5&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-163&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-163&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; show can0&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-163&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If the interface is up, it can be used immediately by FlowFuse.&lt;/p&gt;
&lt;h4 id=&quot;comparison%3A-virtual-vs-physical-can&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#comparison%3A-virtual-vs-physical-can&quot;&gt;Comparison: Virtual vs Physical CAN&lt;/a&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Virtual CAN (vcan)&lt;/th&gt;
&lt;th&gt;Physical CAN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hardware required&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electrical bus&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bitrate configuration&lt;/td&gt;
&lt;td&gt;Not required&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel driver&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vcan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hardware-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlowFuse (Node-RED) flows&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical use&lt;/td&gt;
&lt;td&gt;Development, testing&lt;/td&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;using-socketcan-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#using-socketcan-in-flowfuse&quot;&gt;Using SocketCAN in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once a CAN interface (&lt;code&gt;vcan0&lt;/code&gt; or &lt;code&gt;can0&lt;/code&gt;) is enabled at the operating system level, FlowFuse can interact with it like any other SocketCAN-compatible application. At this stage, no CAN frames are flowing yet. FlowFuse simply gains access to the interface.&lt;/p&gt;
&lt;p&gt;In this section, we&#39;ll focus on how FlowFuse connects to SocketCAN and what that means conceptually, before building any actual flows.&lt;/p&gt;
&lt;p&gt;The flow looks like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;diagram illustrating the connection flow from FlowFuse, through the SocketCAN layer, down to the OS-level CAN interface (vcan0 or can0)&quot; alt=&quot;Diagram illustrating the connection flow from FlowFuse, through the SocketCAN layer, down to the OS-level CAN interface (vcan0 or can0)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-to-canbus.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse does not communicate directly with CAN hardware. Instead, it relies on SocketCAN, which exposes CAN interfaces through the Linux networking stack.&lt;/p&gt;
&lt;p&gt;Once a CAN interface is enabled at the operating system level, whether a virtual interface like vcan0 or a physical interface like can0, it becomes available to any SocketCAN-compatible application. FlowFuse simply opens this interface and exchanges CAN frames using standard socket operations.&lt;/p&gt;
&lt;p&gt;This design has two important advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FlowFuse remains hardware-agnostic. The same flows work with virtual CAN interfaces, USB-to-CAN adapters, or embedded CAN controllers.&lt;/li&gt;
&lt;li&gt;All hardware-specific configuration, such as driver loading and bitrate setup, is handled by the operating system, not by FlowFuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result, the application logic in FlowFuse stays the same across development, testing, and production environments. The only requirement is that the appropriate CAN interface is created and enabled before FlowFuse starts&lt;/p&gt;
&lt;h4 id=&quot;installing-the-socketcan-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#installing-the-socketcan-node&quot;&gt;Installing the SocketCAN Node&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;FlowFuse does not include native CAN support out of the box. To interact with SocketCAN interfaces (&lt;code&gt;can0&lt;/code&gt;, &lt;code&gt;vcan0&lt;/code&gt;, etc.), you need to install a module that provides CAN input and output nodes.&lt;/p&gt;
&lt;p&gt;Follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Instance editor in your browser&lt;/li&gt;
&lt;li&gt;Click the menu icon (☰) in the top-right corner&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-socketcan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; next to the package&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, the SocketCAN nodes will appear in the FlowFuse palette.&lt;/p&gt;
&lt;h5 id=&quot;installation-troubleshooting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#installation-troubleshooting&quot;&gt;Installation Troubleshooting&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;If the installation fails, it is usually due to one of the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FlowFuse is not running on a Linux system (SocketCAN is Linux-only)&lt;/li&gt;
&lt;li&gt;Required build tools are missing on the system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To resolve this, ensure you are running on Linux and install the required build dependencies:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-357&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-357&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; build-essential&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-357&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;After installing the build tools, retry installing &lt;code&gt;node-red-contrib-socketcan&lt;/code&gt; from the FlowFuse palette.&lt;/p&gt;
&lt;h3 id=&quot;working-with-can-frames-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#working-with-can-frames-in-flowfuse&quot;&gt;Working with CAN Frames in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once a CAN interface (&lt;code&gt;vcan0&lt;/code&gt; or &lt;code&gt;can0&lt;/code&gt;) is enabled and the SocketCAN nodes are installed, FlowFuse can begin exchanging CAN frames. At a high level, there are only &lt;strong&gt;two operations&lt;/strong&gt; involved when working with CAN in FlowFuse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Receiving CAN frames&lt;/strong&gt; from the bus&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transmitting CAN frames&lt;/strong&gt; onto the bus&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse represents these operations using dedicated input and output nodes provided by the SocketCAN module.&lt;/p&gt;
&lt;h4 id=&quot;receiving-can-frames&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#receiving-can-frames&quot;&gt;Receiving CAN Frames&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Receiving CAN frames means listening to all messages that appear on the CAN bus and processing them inside FlowFuse.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;code&gt;socketcan-out&lt;/code&gt; node from the FlowFuse palette onto the canvas.&lt;/li&gt;
&lt;li&gt;Open the node configuration and add the interface by clicking the &lt;strong&gt;+&lt;/strong&gt; button next to the interface. Enter your interface name, e.g., &lt;code&gt;vcan0&lt;/code&gt; (for virtual CAN) or &lt;code&gt;can0&lt;/code&gt; (for physical CAN).&lt;/li&gt;
&lt;li&gt;Click Add, then Done to save the interface.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;code&gt;socketcan-out&lt;/code&gt; node to a &lt;strong&gt;Debug&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the flow to begin receiving CAN frames.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once connected, the &lt;code&gt;socketcan-out&lt;/code&gt; node will show a green status box with text. The same applies to the &lt;code&gt;socketcan-in&lt;/code&gt; node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;connected &amp;lt;your-interface-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When frames are received, FlowFuse outputs them as JavaScript objects containing fields such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt;: the time the frame was received (in milliseconds since epoch)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ext&lt;/code&gt;: indicates whether the frame uses an &lt;strong&gt;extended CAN ID&lt;/strong&gt; (true/false)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;canid&lt;/code&gt;: the &lt;strong&gt;CAN identifier&lt;/strong&gt; for the message&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dlc&lt;/code&gt;: the &lt;strong&gt;Data Length Code&lt;/strong&gt;, i.e., the number of data bytes in the frame&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rtr&lt;/code&gt;: &lt;strong&gt;Remote Transmission Request&lt;/strong&gt; flag (true if the frame requests data)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt;: an array of bytes representing the &lt;strong&gt;payload&lt;/strong&gt; of the frame&lt;/li&gt;
&lt;li&gt;&lt;code&gt;err&lt;/code&gt;: indicates whether the frame contains an &lt;strong&gt;error&lt;/strong&gt; (true/false)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rawData&lt;/code&gt;: a copy of the data payload in its &lt;strong&gt;raw byte form&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Debug output showing a received CAN message in FlowFuse&quot; alt=&quot;Debug output showing a received CAN message in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/debug-output-can-message.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This makes it easy to filter, decode, or route messages using standard FlowFuse nodes.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;MoL3vw9x5eg&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/02/images/receiving-can.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Receiving CAN Frames&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h4 id=&quot;transmitting-can-frames&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#transmitting-can-frames&quot;&gt;Transmitting CAN Frames&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Transmitting CAN frames means sending messages onto the CAN bus from FlowFuse. This allows you to control devices, trigger actions, or communicate with other ECUs on the network.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;code&gt;socketcan-in&lt;/code&gt; node from the FlowFuse palette onto the canvas.&lt;/li&gt;
&lt;li&gt;Open the node configuration and set the interface to &lt;code&gt;vcan0&lt;/code&gt; (for virtual CAN) or &lt;code&gt;can0&lt;/code&gt; (for physical CAN).&lt;/li&gt;
&lt;li&gt;Leave the node in &lt;strong&gt;transmit&lt;/strong&gt; mode to send messages onto the bus.&lt;/li&gt;
&lt;li&gt;Connect the input of the &lt;code&gt;socketcan-in&lt;/code&gt; node to any source node, such as an &lt;strong&gt;Inject&lt;/strong&gt; node for testing.&lt;/li&gt;
&lt;li&gt;Configure the message in the &lt;strong&gt;Inject&lt;/strong&gt; node by setting the payload as a JavaScript object containing the fields &lt;code&gt;canid&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;, and optionally &lt;code&gt;ext&lt;/code&gt; for extended frames.&lt;/li&gt;
&lt;li&gt;Deploy the flow to begin transmitting CAN frames.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, a message object could look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-514&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-514&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;canid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;ext&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-514&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This would send a standard CAN frame with ID &lt;code&gt;0x200&lt;/code&gt; and 4 bytes of data onto the bus.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;oWI3Fs9_gyI&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/02/images/transmitting-can.png&#39;); background-size: cover; background-position: center;&quot; title=&quot;Transmitting CAN Frames&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h5 id=&quot;string-formatted-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#string-formatted-messages&quot;&gt;String-Formatted Messages&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Alternatively, CAN messages can be defined as strings using a compact format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;canid&amp;gt;#{R|data}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;canid&lt;/strong&gt;: The CAN identifier in hexadecimal format. For standard IDs using this string format, specify 1-2 hex digits (e.g., &lt;code&gt;5A&lt;/code&gt;, &lt;code&gt;FF&lt;/code&gt;). For extended IDs, use 3 or more hex digits (e.g., &lt;code&gt;7FF&lt;/code&gt;, &lt;code&gt;1F334455&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;data&lt;/strong&gt;: The data payload for the CAN frame, specified in hexadecimal format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;: Indicates a Remote Transmission Request (RTR) frame instead of a data frame.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;200#162DAAFF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sends a CAN frame with ID &lt;code&gt;0x200&lt;/code&gt; and data bytes &lt;code&gt;[0x16, 0x2D, 0xAA, 0xFF]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To send an RTR frame:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;200#R
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requests data from devices listening to CAN ID &lt;code&gt;0x200&lt;/code&gt; without sending any payload.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/getting-started-with-canbus/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By combining SocketCAN with FlowFuse, you&#39;ve eliminated much of the complexity traditionally associated with CAN bus development. What once required low-level C code, vendor-specific drivers, and deep protocol knowledge can now be accomplished with visual flows and straightforward message handling.&lt;/p&gt;
&lt;p&gt;The real power of this approach becomes clear when you consider scalability. The same FlowFuse flows work identically whether you&#39;re testing with a virtual CAN interface on your laptop or deploying to production hardware with physical CAN controllers. The abstraction layer provided by SocketCAN means your application logic remains stable even as your hardware requirements evolve.&lt;/p&gt;
&lt;p&gt;Once you&#39;ve connected to your CAN bus, the possibilities expand significantly. You can build real-time monitoring dashboards to visualize CAN data, send telemetry to cloud platforms for analytics and storage, or bridge CAN networks with virtually any other protocol or system. FlowFuse&#39;s extensive ecosystem of nodes and integrations supports connections to databases, MQTT brokers, REST APIs, industrial protocols, and more, making it straightforward to integrate your CAN infrastructure into larger IoT and automation workflows.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/</id>
        <title>FlowFuse 2.27: Integrated Editor in Remote Instances &amp; Context-Aware FlowFuse Expert</title>
        <summary>A more consistent Node-RED experience across environments and deeper live context for FlowFuse Expert.</summary>
        <updated>2026-02-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/"/>
        <author><name>Jamie Strusz</name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.27 tightens the development loop for Remote instances and makes FlowFuse Expert more aware of what is actually running in your Node-RED environment. It also improves availability for High Availability hosted deployments.&lt;/p&gt;
&lt;h2 id=&quot;a-more-integrated-remote-development-workflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#a-more-integrated-remote-development-workflow&quot;&gt;A More Integrated Remote Development Workflow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Teams run production and edge workloads in Remote instances. When tooling behaves differently across environments, it slows debugging and increases risk during active changes.&lt;/p&gt;
&lt;h3 id=&quot;immersive-editor-%26-snapshot-restore&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#immersive-editor-%26-snapshot-restore&quot;&gt;Immersive Editor &amp;amp; Snapshot Restore&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse now brings the integrated editor experience to Remote instances. Clicking &lt;strong&gt;Open Editor&lt;/strong&gt; provides the same FlowFuse capabilities regardless of where your instance runs.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Immersive Mode on a Remote Instance&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/remote-instance-immersive.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Immersive Mode accessed from a remote instance&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Device Agent v3.8.0 also allows you to restore snapshots while remaining in developer mode. You no longer need to exit developer mode to roll back changes. Pipeline protections remain in place, but manual recovery is faster.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Restoring a snapshot while in Developer Mode&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshot-restore.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Restoring a snapshot without leaving developer mode&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;in-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#in-practice&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You move between hosted and remote environments without changing your workflow&lt;/li&gt;
&lt;li&gt;You restore snapshots without interrupting active debugging&lt;/li&gt;
&lt;li&gt;You reduce friction while iterating on live systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flowfuse-expert-uses-live-flow-and-palette-context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#flowfuse-expert-uses-live-flow-and-palette-context&quot;&gt;FlowFuse Expert Uses Live Flow and Palette Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI guidance is only useful when it reflects what is actually running in your environment. Manually describing flows or installed nodes slows troubleshooting and introduces gaps in context.&lt;/p&gt;
&lt;h3 id=&quot;palette-awareness-%26-flow-context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#palette-awareness-%26-flow-context&quot;&gt;Palette Awareness &amp;amp; Flow Context&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Expert now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understands your selected flows as troubleshooting context&lt;/li&gt;
&lt;li&gt;Detects installed custom nodes automatically&lt;/li&gt;
&lt;li&gt;Answers questions about your Node-RED palette, including versions, updates, and disabled nodes&lt;/li&gt;
&lt;li&gt;Suggests node packages and links directly to manage them&lt;/li&gt;
&lt;li&gt;Installs suggested nodes and imports flows with a single click&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse Expert surfaces context and performs actions only when initiated by the user.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert using live palette context&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-expert-palette-context.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert answering palette queries with live context&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;in-practice-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#in-practice-1&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You do not manually describe your setup&lt;/li&gt;
&lt;li&gt;You identify missing or outdated nodes faster&lt;/li&gt;
&lt;li&gt;You troubleshoot flows based on real context&lt;/li&gt;
&lt;li&gt;You move between chat, palette manager, and editor without unnecessary clicks or context switching&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;high-availability-improvements-for-hosted-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#high-availability-improvements-for-hosted-instances&quot;&gt;High Availability Improvements for Hosted Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Parallel restarts in HA environments can introduce avoidable service interruption during deploys or manual restarts.&lt;/p&gt;
&lt;h3 id=&quot;rolling-restarts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#rolling-restarts&quot;&gt;Rolling Restarts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hosted Node-RED instances with HA enabled now restart sequentially rather than in parallel. Any manual or pipeline-triggered restart follows this behavior.&lt;/p&gt;
&lt;p&gt;This feature is available to Enterprise licensed self-hosted users and Enterprise tier users of FlowFuse Cloud.&lt;/p&gt;
&lt;h3 id=&quot;in-practice-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#in-practice-2&quot;&gt;In practice&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You reduce service interruption during restarts&lt;/li&gt;
&lt;li&gt;You improve availability during deploys&lt;/li&gt;
&lt;li&gt;You maintain stronger continuity in HA environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For detailed breakdowns of each feature with additional visuals, visit our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;changelog&lt;/a&gt;. For the complete list of everything included in FlowFuse 2.27, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If something in this release improves your workflow, or if there is still friction we can remove, please &lt;a href=&quot;mailto:contact@flowfuse.com?subject=Feedback%20on%202.27/&quot;&gt;share feedback or report issues regarding this release&lt;/a&gt; to us.&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The fastest way to get started is with FlowFuse Cloud.&lt;br /&gt;
&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/flowfuse-release-2-27/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run FlowFuse locally using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/</id>
        <title>Event-Driven Architecture: 99% of Your System Requests Are Worthless</title>
        <summary>What Happens When Your Factory Stops Asking and Starts Listening</summary>
        <updated>2026-02-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Nearly 99% of the requests your manufacturing systems make return the same answer: nothing changed. The 1% that matter? You find out too late. This isn&#39;t a monitoring problem. It&#39;s an architecture problem.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Event-Driven Architecture (EDA) flips this model entirely. Instead of systems asking questions on a schedule, they listen for events and react the moment something happens, eliminating the gap between occurrence and response.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In manufacturing, an &amp;quot;event&amp;quot; is any significant occurrence. A machine completes a cycle. A sensor detects an anomaly. A part fails inspection. Inventory hits a threshold. When these events occur, they are immediately broadcast to all interested systems, which respond automatically and in parallel.&lt;/p&gt;
&lt;p&gt;When a machine finishes a production run, it triggers an event. Instantly, the inventory system updates stock levels. Maintenance logs machine hours. Quality control schedules an inspection. Production planning releases the next order. No manual intervention. No waiting.&lt;/p&gt;
&lt;p&gt;This is what real-time responsiveness looks like in practice. Faster issue detection, dynamic optimization, and the ability to absorb disruptions before they cascade.&lt;/p&gt;
&lt;h2 id=&quot;the-structural-limits-of-traditional-manufacturing-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/#the-structural-limits-of-traditional-manufacturing-systems&quot;&gt;The Structural Limits of Traditional Manufacturing Systems&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Traditional manufacturing systems operate on request-response models. The MES queries the ERP for inventory counts. SCADA polls sensors at fixed intervals. Quality systems run batch processes to aggregate data. Each system asks for what it needs, when it needs it. This worked when manufacturing moved slowly. It breaks down in modern production environments.&lt;/p&gt;
&lt;p&gt;The waste is structural. Nearly 99 out of every 100 polling requests return no new information, and polling models consume orders of magnitude more server resources than event-driven alternatives to maintain the same data freshness. Bandwidth and processing power are spent confirming that nothing has changed.&lt;/p&gt;
&lt;p&gt;Between polling intervals lies real risk. A fault appears on the floor at 9:14:01 AM. The monitoring system, configured to poll every five minutes, won&#39;t detect it until 9:15:00. During those 59 seconds, defective output flows downstream while costs accumulate at rates exceeding $38,000 per minute in automotive facilities. Schedules drift. Quality issues propagate. The gap between what&#39;s happening and what the business knows keeps widening.&lt;/p&gt;
&lt;p&gt;Point-to-point integrations make this worse. Connection counts follow the n(n-1)/2 formula. Five systems require ten connections. Ten systems demand 45. Each connection carries its own protocol, authentication scheme, and maintenance overhead. A firmware update means manual remapping across dozens of endpoints. New functionality requires weeks of integration work. A single failure can cascade through every tightly coupled system downstream.&lt;/p&gt;
&lt;p&gt;The architecture that once enabled the factory now constrains it.&lt;/p&gt;
&lt;h2 id=&quot;how-event-driven-architecture-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/#how-event-driven-architecture-works&quot;&gt;How Event-Driven Architecture Works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every polling system works the same way. Your MES wakes up on a timer and asks if anything changed. Usually nothing has. So it waits, then asks again. Multiply this across every system pair on your floor and you have an architecture that spends most of its energy confirming that nothing has happened.&lt;/p&gt;
&lt;p&gt;EDA inverts this. Every significant occurrence gets broadcast the moment it happens. Any system that needs to know receives it immediately. Systems that don&#39;t are never involved.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Diagram comparing traditional polling-based manufacturing systems with event-driven architecture, showing delayed fault detection in polling versus instant system notification using an event broker&quot; alt=&quot;Diagram comparing traditional polling-based manufacturing systems with event-driven architecture, showing delayed fault detection in polling versus instant system notification using an event broker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/polling-vs-eda.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Three components make this possible. Event producers generate the signal. PLCs, sensors, vision systems. Their only responsibility is to announce what happened. Event consumers act on it. The MES updates work orders. The ERP adjusts inventory. The maintenance platform logs runtime hours. Each subscribes only to relevant events and acts independently, so multiple consumers can respond to the same event simultaneously. The event broker connects them without coupling them. It receives events, routes them to subscribers, and keeps a durable log. Neither side needs to know the other exists. Adding a new consumer means subscribing it to the broker. Nothing else changes.&lt;/p&gt;
&lt;p&gt;That last property is what solves the integration complexity problem. In point-to-point architectures, every new connection requires negotiated APIs and coordinated work across teams. The broker absorbs that complexity entirely.&lt;/p&gt;
&lt;p&gt;The durable log solves a problem polling handles poorly. Events that occur while a system is offline are replayed in order when it comes back. Transient outages stop being data integrity problems. The record of what happened on the floor stays complete regardless of which systems were available when it happened.&lt;/p&gt;
&lt;h2 id=&quot;the-business-impact-of-running-on-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/#the-business-impact-of-running-on-events&quot;&gt;The Business Impact of Running on Events&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most factories don&#39;t lose money because their equipment is bad. They lose it because their systems are slow to know what&#39;s happening and slower to act on it.&lt;/p&gt;
&lt;p&gt;That slowness isn&#39;t a people problem. It&#39;s structural. When your systems communicate by asking rather than listening, there&#39;s always a gap between what&#39;s happening on the floor and what the business knows about it. Teams fill that gap with buffers, manual checkpoints, and end-of-shift reports. It works until it doesn&#39;t.&lt;/p&gt;
&lt;p&gt;EDA closes that gap. When something happens, every system that needs to know finds out immediately. The right processes trigger automatically. No polling cycle. No batch job. No one manually connecting the dots.&lt;/p&gt;
&lt;p&gt;The scale of what&#39;s at stake makes this worth stating plainly. Unscheduled downtime costs the world&#39;s largest manufacturers trillions annually, representing a double-digit percentage of revenue. Nearly three-quarters of manufacturing leaders report that delays in reporting problems trigger chain reactions across their operations. These aren&#39;t technology metrics. They&#39;re business outcomes produced by architectures that were never designed to respond in real time.&lt;/p&gt;
&lt;p&gt;Quality compounds the same way. The 1-10-100 rule of manufacturing quality states that a defect costs $1 to catch pre-production, $10 to catch during production, and $100 once it reaches the customer. Every minute a failed inspection goes unbroadcast to downstream systems, that multiplier is running. EDA stops the propagation at the source by ensuring the result is instantly visible to every process that needs to act on it.&lt;/p&gt;
&lt;p&gt;Integration debt follows the same logic. Enterprise-level manufacturing software implementations routinely take many months to multiple years. Every new capability your team wants requires a project. EDA changes the economics entirely. New systems subscribe to the broker. Existing systems stay untouched. What once consumed quarters now requires configuration.&lt;/p&gt;
&lt;p&gt;And when something does go wrong, you have a complete timestamped record of everything that happened on the floor. Not reconstructed timelines. Root cause analysis that took days takes hours. Audits have a chain of custody by default.&lt;/p&gt;
&lt;p&gt;The factories pulling ahead right now aren&#39;t the most automated. They&#39;re the ones where information moves as fast as production does. Every minute that gap exists, it has a cost. EDA removes it.&lt;/p&gt;
&lt;h2 id=&quot;what-it-takes-to-move-to-event-driven-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/#what-it-takes-to-move-to-event-driven-architecture&quot;&gt;What It Takes to Move to Event-Driven Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hardware is already there. Sensors, &lt;a href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/&quot;&gt;PLCs&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;SCADA systems&lt;/a&gt;. All running. EDA doesn&#39;t replace them. It changes how they communicate.&lt;/p&gt;
&lt;p&gt;You need an event broker and something that connects to legacy systems. &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; for shop floor devices. Kafka for enterprise loads. &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; to bridge the gap. That&#39;s the stack.&lt;/p&gt;
&lt;p&gt;The real work is defining what counts as an event. A sensor produces tens of thousands of readings per day. Broadcasting all of them is noise. The event is when temperature crosses a threshold, stays abnormal, or trends wrong. Exceptions, not data points.&lt;/p&gt;
&lt;p&gt;Your team already knows which deviations matter. Which delays cascade. Which variations are normal. Get this wrong and you build a system that generates alerts faster than anyone can ignore them.&lt;/p&gt;
&lt;p&gt;Start where waiting costs the most. Downtime reported late doesn’t need better sensors. The stop event needs to fire when it happens and route to maintenance, scheduling, and analytics simultaneously. One workflow. Measured impact. Studies show event-driven systems responding in milliseconds rather than minutes, reducing manual intervention dramatically and improving process completion rates at scale. Prove it on one line, then expand to the next bottleneck.&lt;/p&gt;
&lt;p&gt;The broker is straightforward. The translation layer isn&#39;t. Your &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;MES&lt;/a&gt; doesn&#39;t listen for events. Your &lt;a href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/&quot;&gt;ERP&lt;/a&gt; expects scheduled queries. Your quality system runs batch jobs. Bridging that gap is where real effort lives.&lt;/p&gt;
&lt;p&gt;Brownfield doesn’t require cutover. Legacy runs. New workflows build on events. Each migration reduces polling overhead and creates durable audit trails. Value compounds.&lt;/p&gt;
&lt;p&gt;The factories that fail treat this as infrastructure. The ones that succeed pick the highest-cost delay, fix it with events, measure the difference, and move on. Value drives adoption. Not architecture diagrams.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;FlowFuse makes event-driven architecture practical for manufacturing by connecting IT and OT systems through a single platform that supports virtually any protocol, includes a built-in MQTT broker, and provides enterprise-grade deployment and security. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started with FlowFuse today&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;sources-%26-references&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/what-is-event-driven-architecture-in-manufacturing/#sources-%26-references&quot;&gt;Sources &amp;amp; References&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;APIPark — &lt;em&gt;Moving Beyond API Polling to Asynchronous Architectures&lt;/em&gt;
&lt;a href=&quot;https://apipark.com/technews/TbhGSEzF.html&quot;&gt;https://apipark.com/technews/TbhGSEzF.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DZone — &lt;em&gt;Webhooks vs. Polling: You’re Better Than This&lt;/em&gt;
&lt;a href=&quot;https://dzone.com/articles/webhooks-vs-polling-youre-better-than-this-1&quot;&gt;https://dzone.com/articles/webhooks-vs-polling-youre-better-than-this-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Insane Cyber — &lt;em&gt;The Real Cost of Industrial Downtime&lt;/em&gt;
&lt;a href=&quot;https://insanecyber.com/real-cost-industrial-downtime/&quot;&gt;https://insanecyber.com/real-cost-industrial-downtime/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;StackSync — &lt;em&gt;Why Integration Complexity Grows Exponentially&lt;/em&gt;
&lt;a href=&quot;https://www.stacksync.com/blog/integration-complexity-growth&quot;&gt;https://www.stacksync.com/blog/integration-complexity-growth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Siemens — &lt;em&gt;The Cost of Downtime in Manufacturing&lt;/em&gt;
&lt;a href=&quot;https://www.siemens.com/global/en/products/services/industry-operations-services/digital-enterprise-services/manufacturing-operations-management/manufacturing-intelligence/downtime-cost.html&quot;&gt;https://www.siemens.com/global/en/products/services/industry-operations-services/digital-enterprise-services/manufacturing-operations-management/manufacturing-intelligence/downtime-cost.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rockwell Automation — &lt;em&gt;The True Cost of Downtime&lt;/em&gt;
&lt;a href=&quot;https://www.rockwellautomation.com/en-us/company/news/blogs/the-cost-of-downtime.html&quot;&gt;https://www.rockwellautomation.com/en-us/company/news/blogs/the-cost-of-downtime.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;American Society for Quality (ASQ) — &lt;em&gt;Cost of Quality and the 1-10-100 Rule&lt;/em&gt;
&lt;a href=&quot;https://asq.org/quality-resources/cost-of-quality&quot;&gt;https://asq.org/quality-resources/cost-of-quality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gartner — &lt;em&gt;Manufacturing ERP Implementation Timelines&lt;/em&gt;
&lt;a href=&quot;https://www.gartner.com/en/documents/manufacturing-erp-implementation&quot;&gt;https://www.gartner.com/en/documents/manufacturing-erp-implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;International Journal of Science and Advanced Technology (IJSAT) — &lt;em&gt;Event-Driven Manufacturing Automation Systems&lt;/em&gt;
&lt;a href=&quot;https://www.ijsat.org/papers/2025/1/2907.pdf&quot;&gt;https://www.ijsat.org/papers/2025/1/2907.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/</id>
        <title>Shop Floor AI: Dead on Arrival Without This</title>
        <summary>Why your industrial AI fails before it even starts - and the missing architecture that fixes it</summary>
        <updated>2026-02-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Your industrial AI initiative is dying. Maybe it&#39;s already dead.&lt;/p&gt;
&lt;p&gt;Not because the models are wrong. Not because the data scientists failed. Not because you didn&#39;t spend enough on sensors or compute power.&lt;/p&gt;
&lt;p&gt;It&#39;s dying because you&#39;re building on a foundation that was never designed to support it.&lt;/p&gt;
&lt;p&gt;You instrumented everything: motors, conveyors, bearings, valves, streaming thousands of data points per second. Historians filled to capacity. Dashboards displayed every metric. AI models trained on millions of records. Yet despite all this technology, you still can&#39;t see what&#39;s happening until something breaks.&lt;/p&gt;
&lt;p&gt;The problem isn&#39;t your AI. It&#39;s the architecture underneath it.&lt;/p&gt;
&lt;p&gt;This article reveals why most industrial AI projects fail before they start: why raw signals without context are just noise, why your three disconnected data layers doom AI from day one, and why a Unified Namespace is the only architecture that makes industrial AI actually work on the shop floor.&lt;/p&gt;
&lt;p&gt;Twenty years ago, a skilled operator could diagnose a failing machine by sound, smell, or vibration. Today&#39;s machines still communicate just as clearly. They&#39;ve simply switched languages. They produce numbers that nobody understands. A temperature spike, a current drift, a vibration anomaly: each is meaningless without knowing which product is running, under what conditions, with which maintenance history, and how this system typically behaves.&lt;/p&gt;
&lt;p&gt;The problem isn&#39;t AI capability. It&#39;s poor architecture. Signals without context are difficult to interpret. Context without connection never reaches the people who need it. And decisions made without information are guesses at best.&lt;/p&gt;
&lt;p&gt;For AI to actually work on the factory floor, we need three things working in concert: signals that feed context, context that creates understanding, and AI that empowers humans to ask the right questions at the right time.&lt;/p&gt;
&lt;h2 id=&quot;the-three-layer-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#the-three-layer-problem&quot;&gt;The Three-Layer Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most manufacturers diagnose themselves with an AI problem. Their models don&#39;t predict failures. Their anomaly detection drowns in false positives. Their optimization recommendations get politely ignored.&lt;/p&gt;
&lt;p&gt;They&#39;re diagnosing the wrong disease. Most factory floors aren&#39;t ready for AI.&lt;/p&gt;
&lt;p&gt;This isn&#39;t an AI problem. It&#39;s an architecture problem that AI just makes impossible to ignore. Your data exists in three disconnected layers, and until you bridge them, no amount of machine learning can help.&lt;/p&gt;
&lt;h3 id=&quot;layer-one%3A-the-signal-layer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#layer-one%3A-the-signal-layer&quot;&gt;Layer One: The Signal Layer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Raw data accumulates here. PLCs, SCADA, historians, MES systems, all generating measurements at rates human cognition was never designed to process. Temperature, pressure, flow, current draw, RPM, torque, position. Millisecond timestamps. Perfect fidelity. Absolutely zero meaning.&lt;/p&gt;
&lt;p&gt;The signal layer has no concept of importance. When a conveyor motor pulls 2.3 amps, that&#39;s just a number in a database. The system doesn&#39;t know if this represents peak efficiency or the warning sign of a dying gearbox.&lt;/p&gt;
&lt;p&gt;But nobody knows which question to ask until something fails. Then you&#39;re analyzing historical data files, reconstructing what happened. It&#39;s post-incident analysis when what you needed was real-time diagnosis.&lt;/p&gt;
&lt;p&gt;The signal layer does exactly one thing well: it remembers everything. What it can&#39;t do is understand anything.&lt;/p&gt;
&lt;h3 id=&quot;layer-two%3A-the-context-layer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#layer-two%3A-the-context-layer&quot;&gt;Layer Two: The Context Layer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Context is everything the signal doesn&#39;t tell you. Which product is currently running. The ambient conditions. The maintenance history. The supplier change that wasn&#39;t documented. The operator who runs things hot because it&#39;s faster. The firmware update that altered control loop timing.&lt;/p&gt;
&lt;p&gt;This layer exists in fragments, scattered across ERP systems, maintenance logs, Excel files, shift handover notes, and inside the heads of people who might retire next year.&lt;/p&gt;
&lt;p&gt;Without this layer, signals are just sequential numbers. With it, they become useful information. They tell you not just what is happening, but why it matters, what it resembles, and what typically comes next.&lt;/p&gt;
&lt;p&gt;The fundamental problem: we never built systems to unite these layers. Different databases, different teams, different vendors, different security models. Integration became a six-month IT project instead of a core design principle.&lt;/p&gt;
&lt;p&gt;Your data has context, but it&#39;s locked away where neither your people nor your AI can see it.&lt;/p&gt;
&lt;h3 id=&quot;layer-three%3A-the-human-decision-layer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#layer-three%3A-the-human-decision-layer&quot;&gt;Layer Three: The Human Decision Layer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is where humans operate, increasingly overwhelmed by the gap between what they can see and what they need to know.&lt;/p&gt;
&lt;p&gt;An alarm sounds. An operator has 30 seconds to decide: Is this real or noise? Critical or routine? Stop the line or log and monitor? The context they need is fragmented across three systems they can&#39;t access and two colleagues on different shifts.&lt;/p&gt;
&lt;p&gt;So they decide based on experience and instinct. Sometimes they&#39;re right. Sometimes they&#39;re not. Either way, the decision logic gets lost - there&#39;s no system capturing why they chose what they did.&lt;/p&gt;
&lt;p&gt;Engineers face the inverse problem: too much time and too much data. By the time they&#39;ve extracted historian data, correlated it with production schedules, and cross-referenced maintenance records, the problem has either resolved itself or gotten worse.&lt;/p&gt;
&lt;p&gt;This is where AI should enter, not as a decision-maker, but as an intelligent assistant. The human decision layer needs AI that can answer questions in real-time: &amp;quot;Is this vibration pattern normal for this product recipe?&amp;quot; &amp;quot;When did we last see this current signature?&amp;quot; &amp;quot;What were the conditions the last three times this alarm triggered?&amp;quot;&lt;/p&gt;
&lt;p&gt;The decision remains human. The insight becomes instant.&lt;/p&gt;
&lt;h2 id=&quot;why-this-architecture-breaks-ai&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#why-this-architecture-breaks-ai&quot;&gt;Why This Architecture Breaks AI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can&#39;t fix a three-layer problem with a one-layer solution.&lt;/p&gt;
&lt;p&gt;Companies repeatedly make the same mistake: they drop AI models directly into the signal layer (pure time-series analysis on raw sensor data) then wonder why predictions are worthless. The model identifies a pattern, but it&#39;s blind to the fact that context just changed. It flags anomalies that are actually normal for this product recipe. It misses failures because the signal appeared fine while the context indicated problems.&lt;/p&gt;
&lt;p&gt;But here&#39;s what&#39;s crucial to understand: AI is ready for the factory floor right now. Not ready to take autonomous action, but ready to be the most knowledgeable assistant your operators and engineers have ever had.&lt;/p&gt;
&lt;p&gt;Think about what you actually need. When an operator sees unusual behavior, they need answers immediately: &amp;quot;Is this normal?&amp;quot; &amp;quot;What happened last time?&amp;quot; &amp;quot;Should I be concerned?&amp;quot; When an engineer investigates a problem, they need to explore data at depth: &amp;quot;Show me all the times we saw this pattern.&amp;quot; &amp;quot;What were the ambient conditions?&amp;quot; &amp;quot;How does this compare across shifts?&amp;quot;&lt;/p&gt;
&lt;p&gt;AI can answer these questions instantly if it has access to the right architecture.&lt;/p&gt;
&lt;p&gt;Industrial AI fails when you ignore the architecture. You need the signal layer feeding a context layer that&#39;s actually integrated, queryable, and current. You need decision support that operates at the speed questions get asked, not at the speed IT can generate a report.&lt;/p&gt;
&lt;h2 id=&quot;the-architecture-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#the-architecture-solution&quot;&gt;The Architecture Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The challenge isn&#39;t the layers themselves, but the gaps between them.&lt;/p&gt;
&lt;p&gt;So what would an architecture look like that actually closes these gaps? What would it take to have signals arrive already carrying context? To have that context accessible the moment a question gets asked? To give AI and humans the same unified view of what&#39;s happening right now?&lt;/p&gt;
&lt;p&gt;The requirements are clear: you need operational data organized the way factories actually run - by site, area, line, and asset. You need context added at the moment data enters the system, not reconstructed hours later. You need a single source of truth that every system can access in real time.&lt;/p&gt;
&lt;p&gt;This isn&#39;t a future vision. This architecture exists, and it&#39;s been battle-tested in manufacturing operations worldwide.&lt;/p&gt;
&lt;p&gt;It&#39;s called the &lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A Unified Namespace is a shared, real-time, event-driven structure where operational data flows with its context intact. Instead of systems integrating point-to-point, every system publishes to and consumes from the same namespace. Signals arrive already carrying context.&lt;/p&gt;
&lt;p&gt;In a UNS, a motor current is no longer just a number stored in a historian. It&#39;s published as &lt;em&gt;Line 3 / Conveyor 2B / Motor Current&lt;/em&gt;, alongside the active recipe, operating mode, ambient conditions, and relevant maintenance history. Every system sees the same structured truth, continuously updated.&lt;/p&gt;
&lt;p&gt;This shift in architecture is what makes AI viable on the factory floor.&lt;/p&gt;
&lt;p&gt;Building a Unified Namespace requires three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connecting incompatible industrial systems&lt;/li&gt;
&lt;li&gt;Enriching raw signals with operational context as data flows&lt;/li&gt;
&lt;li&gt;Publishing that context once, over MQTT, so AI and humans can consume it in real time&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is where flow-based integration becomes essential.&lt;/p&gt;
&lt;p&gt;Tools like &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; make UNS architectures practical. Instead of writing custom integration code, engineers visually wire systems together. PLCs publishing over Modbus, MES systems exposing REST APIs, and proprietary SCADA protocols can all be connected, normalized, and enriched as data moves through the flows.&lt;/p&gt;
&lt;p&gt;FlowFuse builds on Node-RED to make this architecture production-ready. It adds centralized deployment, version control, access control, and remote management: the capabilities required to operate a Unified Namespace reliably across lines, plants, and teams.&lt;/p&gt;
&lt;p&gt;Crucially, in a Unified Namespace, context is added at the moment data enters the system, not reconstructed later. A motor current isn&#39;t simply forwarded. It&#39;s enriched with equipment hierarchy, product recipe, operating mode, environmental conditions, and timestamps aligned with production events.&lt;/p&gt;
&lt;p&gt;That enriched information is then published into a shared MQTT-based Namespace. One location. One structure. One source of truth. Dashboards, analytics, and AI systems all subscribe to the same contextualized view of reality.&lt;/p&gt;
&lt;p&gt;Through &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mcp/&quot;&gt;FlowFuse MCP nodes&lt;/a&gt;, AI systems connect directly to the namespace, querying live operational context instead of pulling raw time-series data from isolated historians and attempting to reconstruct meaning after the fact.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/ai/&quot;&gt;FlowFuse AI Expert&lt;/a&gt; operates on the same MCP-backed context layer. Operators and engineers can ask questions in natural language (&lt;em&gt;&amp;quot;Is Line 3 behaving normally?&amp;quot;&lt;/em&gt;, &lt;em&gt;&amp;quot;Have we seen this vibration pattern before?&amp;quot;&lt;/em&gt;, &lt;em&gt;&amp;quot;What changed before the last failure?&amp;quot;&lt;/em&gt;) and receive answers grounded in the live Unified Namespace.&lt;/p&gt;
&lt;p&gt;To learn how to build your own Unified Namespace with FlowFuse, &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;see our comprehensive guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The result is immediate insight without additional tooling, custom integrations, or fragile data pipelines. The architecture already exists. The context is already there. The questions can finally be asked at the speed decisions are made.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/shop-floor-to-ai-signals-context-decisions/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your industrial AI isn&#39;t failing because the models are bad. It&#39;s failing because the architecture was never designed to support it.&lt;/p&gt;
&lt;p&gt;Most manufacturers make the same mistake: they bolt AI onto existing infrastructure - historians full of raw signals, context scattered across disconnected systems, decisions made with incomplete information. Then they wonder why predictions are worthless and anomaly detection drowns in false positives.&lt;/p&gt;
&lt;p&gt;You can&#39;t solve a three-layer problem with a one-layer solution.&lt;/p&gt;
&lt;p&gt;The Unified Namespace fixes this by doing what should have been done from the start: uniting signals with context in real time. A motor current stops being &amp;quot;2.3 amps&amp;quot; in a database and becomes operational intelligence - which line, which equipment, which recipe, what maintenance history, what patterns preceded past failures.&lt;/p&gt;
&lt;p&gt;This is the foundation AI needs. Not more data. Not better models. Context that transforms signals into understanding.&lt;/p&gt;
&lt;p&gt;With this architecture in place, AI shifts from a failed prediction engine to what it should be: a tool that multiplies operational expertise. It doesn&#39;t replace human judgment. It enables faster, better-informed decisions backed by complete operational context.&lt;/p&gt;
&lt;p&gt;Manufacturers who build this architecture first get operations that learn from every incident, engineering teams that diagnose root causes in minutes instead of days, and confidence in decisions because they&#39;re based on understanding rather than guesswork.&lt;/p&gt;
&lt;p&gt;The path forward isn&#39;t better AI models. It&#39;s better architecture. Build the Unified Namespace first. The AI will finally work.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Start with FlowFuse today&lt;/a&gt;. Build the architecture your industrial AI needs to succeed.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/</id>
        <title>Mapping MTConnect Streams for Dashboard Visualization</title>
        <summary>Connect FlowFuse to MTConnect agents and build real-time CNC machine dashboards without custom code.</summary>
        <updated>2026-02-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Most manufacturing facilities run MTConnect agents on their CNC machines, but the XML data these agents produce isn&#39;t directly usable. You receive streams of timestamped measurements, state changes, and condition flags wrapped in hierarchical XML structures. Converting this into a functional dashboard means solving three problems: retrieving the data reliably, parsing it correctly, and routing specific values to the right display components.&lt;/p&gt;
&lt;p&gt;This article walks through the implementation. You&#39;ll connect FlowFuse to an MTConnect agent, extract data items from the XML response, and build dashboard widgets that update in real time.&lt;/p&gt;
&lt;h2 id=&quot;what-mtconnect-is-and-why-it-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#what-mtconnect-is-and-why-it-matters&quot;&gt;What MTConnect Is and Why It Matters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mtconnect.org/getting-started/&quot;&gt;MTConnect&lt;/a&gt; is an open manufacturing standard that defines how equipment communicates operational data. Before MTConnect, each machine tool manufacturer used proprietary protocols. Connecting a Mazak, Haas, and DMG MORI to the same monitoring system meant writing custom integrations for each brand. MTConnect solves this by providing a vendor-neutral protocol that any machine can implement.&lt;/p&gt;
&lt;p&gt;The standard specifies what data machines should report and how to structure it. A spindle speed reading from a Haas looks identical to one from a Mazak when both machines run MTConnect agents. This standardization makes it possible to build dashboards and monitoring systems that work across mixed machine fleets without custom code for each manufacturer.&lt;/p&gt;
&lt;p&gt;MTConnect agents typically run as software on the machine controller or on a separate computer connected to the machine. The agent reads data from the controller&#39;s internal systems and exposes it through HTTP endpoints that return XML. You don&#39;t interact with the machine directly—you interact with the agent.&lt;/p&gt;
&lt;h2 id=&quot;data-types-in-mtconnect&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#data-types-in-mtconnect&quot;&gt;Data Types in MTConnect&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MTConnect organizes data into three categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Samples - Continuous numeric measurements like spindle speed, axis position, temperature, power consumption. These values change smoothly and have units.&lt;/li&gt;
&lt;li&gt;Events - Discrete state changes like mode switches, program starts, door opens. Values are strings or enumerations.&lt;/li&gt;
&lt;li&gt;Condition - Equipment health at the component level: normal, warning, fault, unavailable. Multiple conditions can be active simultaneously.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Agents expose this through HTTP endpoints. /current returns latest values for all data items. /sample?from=X&amp;amp;count=Y returns time-series data.&lt;/p&gt;
&lt;h2 id=&quot;xml-response-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#xml-response-structure&quot;&gt;XML Response Structure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you query an MTConnect agent, the response is an XML document rooted in the &lt;code&gt;Streams&lt;/code&gt; element, which contains one or more &lt;code&gt;DeviceStream&lt;/code&gt; elements—each representing a device or machine.&lt;/p&gt;
&lt;p&gt;Within each &lt;code&gt;DeviceStream&lt;/code&gt;, &lt;code&gt;ComponentStream&lt;/code&gt; elements describe individual machine components such as spindles, axes, or controllers. Each component reports its data using three categories: &lt;code&gt;Samples&lt;/code&gt;, &lt;code&gt;Events&lt;/code&gt;, and &lt;code&gt;Conditions&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Samples represent continuously measured values, while Events represent discrete or state-based changes. Conditions are reported inside a &lt;code&gt;Conditions&lt;/code&gt; container and use state-specific elements—such as &lt;code&gt;Normal&lt;/code&gt;, &lt;code&gt;Warning&lt;/code&gt;, or &lt;code&gt;Fault&lt;/code&gt;—rather than a generic condition element. Multiple condition states may be active at the same time, as long as they represent different condition data items.&lt;/p&gt;
&lt;p&gt;Each reported data item includes a &lt;code&gt;dataItemId&lt;/code&gt; for identification, a &lt;code&gt;timestamp&lt;/code&gt; indicating when the value was recorded, and the value itself provided as text content, for example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-59&quot;&gt;
  &lt;pre class=&quot;language-xml&quot;&gt;&lt;code id=&quot;code-59&quot; class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SpindleSpeed&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;dataItemId&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;S1spd&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2026-01-30T14:23:17.492Z&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;2847&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;SpindleSpeed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-59&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;While this hierarchical structure provides a complete and standardized view of the machine, dashboard implementations must traverse multiple levels of nesting and correlate &lt;code&gt;dataItemId&lt;/code&gt; values with their definitions in the Devices model to extract and display the data they care about.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we understand the structure of MTConnect and the challenges involved, let&#39;s look at how to collect and visualize MTConnect data using FlowFuse.&lt;/p&gt;
&lt;p&gt;FlowFuse is an industrial application platform built on Node-RED that brings data collection, transformation, and visualization together in one place. Instead of writing custom integration code, you build flows visually by dragging, configuring, and connecting nodes, then deploying them—no separate tools required.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse instance&lt;/strong&gt; – An active FlowFuse account with an instance created and access to the Node-RED Editor. Sign up at https://app.flowfuse.com and follow the FlowFuse getting started guide at https://flowfuse.com/docs/user/introduction/#getting-started-with-flowfuse. If you are new to Node-RED, you can also check out our &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;course&lt;/a&gt; on Node-RED.&lt;/li&gt;
&lt;li&gt;MTConnect agent – A CNC machine running an MTConnect agent or an MTConnect simulator such as the public agent at &lt;code&gt;agent.mtconnect.org&lt;/code&gt; or a locally hosted agent&lt;/li&gt;
&lt;li&gt;Network access – Connectivity from the FlowFuse instance to the MTConnect agent&#39;s HTTP endpoint, with the FlowFuse Remote Device Agent installed when connecting from cloud-hosted FlowFuse to on-premises machines&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;collecting-mtconnect-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#collecting-mtconnect-data&quot;&gt;Collecting MTConnect Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Bringing MTConnect data into FlowFuse is the first step toward a live dashboard. While you could use the standard HTTP Request node to query MTConnect agents, which is the most common approach, that method requires manually parsing XML responses and navigating through large nested objects to extract specific data points. In this article, I&#39;ll show you an easier way.&lt;/p&gt;
&lt;p&gt;The Solution Engine node (&lt;code&gt;node-red-contrib-solution-engine&lt;/code&gt;) makes this straightforward because it lets you access any data point directly by its dataItemId, without having to worry about parsing XML or navigating nested structures.&lt;/p&gt;
&lt;p&gt;You can install the node by following the instructions in the FlowFuse documentation: &lt;a href=&quot;https://flowfuse.com/node-red/getting-started/library/#using-the-palette-manager&quot;&gt;Using the Palette Manager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once installed, follow these steps to start collecting data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;code&gt;mtconnect-dataitem&lt;/code&gt; node to your canvas and open its configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the host of your MTConnect agent or broker (for example, &lt;code&gt;mtconnect.isoc.net&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the port your agent is listening on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Path (optional): leave this empty in most cases. The node automatically detects the type of agent or broker and chooses the correct endpoint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For SolutionEngine agents, it uses &lt;code&gt;/api/v6/mtc/current&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For generic MTConnect brokers like &lt;code&gt;mtconnect.isoc.net&lt;/code&gt;, it uses &lt;code&gt;/current&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only fill in this field if your broker uses a custom endpoint that differs from the defaults. Entering &lt;code&gt;/current&lt;/code&gt; manually for standard brokers may cause the node to fail.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the &lt;code&gt;dataItemId&lt;/code&gt; for the value you want to retrieve.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once everything is configured, deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To trigger the node, add an Inject node, set the polling interval you want, and connect it to the &lt;code&gt;mtconnect-dataitem&lt;/code&gt; node. This will fetch the latest data at regular intervals and send it to your dashboard or other nodes in the flow.&lt;/p&gt;
&lt;p&gt;When the node successfully retrieves data, it outputs the following fields: &lt;code&gt;msg.payload&lt;/code&gt; (the value), &lt;code&gt;dataItemId&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;sequence&lt;/code&gt;, and &lt;code&gt;name&lt;/code&gt;. The node also shows the status with a green square when data is found successfully. If the value isn&#39;t available, it will display a yellow square.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MTConnect Data Item node output on debug panel&quot; alt=&quot;MTConnect Data Item node output on debug panel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/output.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-the-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#building-the-dashboard&quot;&gt;Building the Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;re successfully retrieving MTConnect data, the next step is to display it on a live dashboard. FlowFuse makes this straightforward with its &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;dashboard package&lt;/a&gt;. You can bind any data item to a visual component, and it updates automatically whenever new data arrives.&lt;/p&gt;
&lt;p&gt;Before you start, make sure to install the &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; package to add the dashboard nodes.&lt;/p&gt;
&lt;p&gt;For this tutorial, we&#39;ll demonstrate two example data points: Controller Mode and Spindle Speed. You can apply the same steps to all other data points as an exercise. I&#39;m using a public MTConnect demo agent (&lt;a href=&quot;https://demo.mtconnect.org/&quot;&gt;https://demo.mtconnect.org&lt;/a&gt;) to make it easy to follow along.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is a brief demonstration to help you understand the workflow. When building your production dashboard, make sure to use the appropriate host and port for your actual MTConnect agent, and select widgets that best suit your specific monitoring needs and use case.&lt;/p&gt;
&lt;p&gt;I&#39;ve provided additional data points with their &lt;code&gt;dataItemId&lt;/code&gt;s below so you can practice. Try to match the dashboard shown in the image below, or create your own layout by selecting different &lt;code&gt;dataItemId&lt;/code&gt;s and widget types. For more information on available dashboard widgets, see the FlowFuse documentation: &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets&quot;&gt;https://dashboard.flowfuse.com/nodes/widgets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;MTConnect FlowFuse Dashboard at left and MTConnect demo public agent digital twin at right&quot; alt=&quot;MTConnect FlowFuse Dashboard at left and MTConnect demo public agent digital twin at right&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-with-mtconnect-agent-digital-twin.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;available-data-points-for-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#available-data-points-for-practice&quot;&gt;Available Data Points for Practice&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Item ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;execution&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Execution State&lt;/td&gt;
&lt;td&gt;Program execution status (ACTIVE, READY, STOPPED)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doorstate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Door State&lt;/td&gt;
&lt;td&gt;Machine door status (OPEN/CLOSED)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;program&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Program Name&lt;/td&gt;
&lt;td&gt;Currently loaded program name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;activeprog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Active Program&lt;/td&gt;
&lt;td&gt;Currently executing program&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Tool_number&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tool Number&lt;/td&gt;
&lt;td&gt;Active tool number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pallet_num&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pallet Number&lt;/td&gt;
&lt;td&gt;Current pallet identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Xabs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;X-Axis Absolute Position&lt;/td&gt;
&lt;td&gt;Current X-axis absolute position in mm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Zabs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Z-Axis Absolute Position&lt;/td&gt;
&lt;td&gt;Current Z-axis absolute position in mm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Bpos&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;B-Axis Position&lt;/td&gt;
&lt;td&gt;Current B-axis rotational position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cpos&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C-Axis Position&lt;/td&gt;
&lt;td&gt;Current C-axis rotational position&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;steps-to-create-the-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#steps-to-create-the-dashboard&quot;&gt;Steps to Create the Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an Inject node onto the canvas, double-click it, and set Repeat to interval for every 1 second.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag two mtconnect-dataitem nodes onto the canvas and connect them to the inject node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the first mtconnect-dataitem node and configure it: Host: &lt;code&gt;demo.mtconnect.org&lt;/code&gt;, Port: &lt;code&gt;5000&lt;/code&gt;, Data Item ID: &lt;code&gt;mode&lt;/code&gt;. For the second node, use the same configuration except Data Item ID: &lt;code&gt;Srpm&lt;/code&gt;. Click Done for both nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Text widget onto the canvas and double-click it. Click the + button next to Group to create a new group: Group Name: &lt;code&gt;Machine State&lt;/code&gt;, select the page and check Display group name, then click Done.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Text widget configuration: Label: &lt;code&gt;Controller Mode:&lt;/code&gt;, Layout: Select the 4th option, enable Style option, Font: Default, Text Size: &lt;code&gt;26&lt;/code&gt;, then click Done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Text widget configuration settings&quot; alt=&quot;Text widget configuration settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/text-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the mode mtconnect-dataitem node output to the Text widget input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Gauge widget onto the canvas and double-click it. Create a new group: Group Name: &lt;code&gt;Spindle Speed&lt;/code&gt;. In the Gauge widget configuration: Type: Half gauge, Style: Rounded, Value: &lt;code&gt;msg.payload&lt;/code&gt;, Range limits: &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;10000&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add three segments by clicking the + button in the Segments section and configure them as shown in the image below.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Gauge widget configuration settings&quot; alt=&quot;Gauge widget configuration settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/gauge.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the Srpm mtconnect-dataitem node output to the Gauge widget input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Deploy in the top-right corner.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To achieve the page layout as shown in the dashboard I have built, follow the &lt;a href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-page-layout&quot;&gt;Setting Page Layout guide&lt;/a&gt; and set it to Notebook.&lt;/p&gt;
&lt;p&gt;Your dashboard should now display live updates for Controller Mode and Spindle Speed from the MTConnect agent. You can extend this by adding more data items from the table above, experimenting with different widget types, and organizing them into logical groups for your specific monitoring needs.&lt;/p&gt;
&lt;p&gt;Below is the complete flow configuration. If you&#39;ve successfully built the dashboard following the steps above, you can compare it with this reference implementation:&lt;/p&gt;
&lt;div id=&quot;nr-flow-255&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow255 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;5daedf163d8ff55a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Spindle Speed&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;52df691dc45e95db&#92;&quot;,&#92;&quot;95d475e6ecb616fc&#92;&quot;,&#92;&quot;2267147b9ee9cc86&#92;&quot;],&#92;&quot;x&#92;&quot;:134,&#92;&quot;y&#92;&quot;:119,&#92;&quot;w&#92;&quot;:652,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;52df691dc45e95db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5daedf163d8ff55a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Srpm&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;95d475e6ecb616fc&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;95d475e6ecb616fc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5daedf163d8ff55a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Spindle Speed&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9df7f1ad772380dd&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;height&#92;&quot;:3,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;rounded&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;alwaysShowTitle&#92;&quot;:false,&#92;&quot;floatingTitlePosition&#92;&quot;:&#92;&quot;top-left&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;RPM&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#8d8600&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;8000&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#d29d00&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;9500&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ff4013&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;10000&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:680,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2267147b9ee9cc86&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5daedf163d8ff55a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;52df691dc45e95db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9df7f1ad772380dd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Spindle Speed&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;df8568c32d9e9bfa&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;df8568c32d9e9bfa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MTConnect Dashboard&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;34bdc26026de2a48&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;ecea95aad5b94726&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;34bdc26026de2a48&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;ecea95aad5b94726&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#1f2933&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#00a3d7&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#f5f7fa&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#e5e7eb&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine State&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;8f895b1f6bcb91e9&#92;&quot;,&#92;&quot;09c59f876c3785b8&#92;&quot;,&#92;&quot;b83ef79948c36e6d&#92;&quot;,&#92;&quot;8e820966be8f9874&#92;&quot;,&#92;&quot;6fb9250c86c29e88&#92;&quot;,&#92;&quot;2d665d743deeac21&#92;&quot;,&#92;&quot;4df4be8a5a835810&#92;&quot;],&#92;&quot;x&#92;&quot;:134,&#92;&quot;y&#92;&quot;:219,&#92;&quot;w&#92;&quot;:652,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;8f895b1f6bcb91e9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;09c59f876c3785b8&#92;&quot;,&#92;&quot;8e820966be8f9874&#92;&quot;,&#92;&quot;2d665d743deeac21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;09c59f876c3785b8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;mode&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b83ef79948c36e6d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b83ef79948c36e6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;44eef3deae3ebe65&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Controller Mode : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8e820966be8f9874&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;execution&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6fb9250c86c29e88&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6fb9250c86c29e88&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;44eef3deae3ebe65&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Execution : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d665d743deeac21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;doorstate&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4df4be8a5a835810&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4df4be8a5a835810&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;da2bf9f0f5377d70&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;44eef3deae3ebe65&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Door State : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;44eef3deae3ebe65&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine State&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;df8568c32d9e9bfa&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Program &amp;amp; Tool&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;df36b3a29c31ce98&#92;&quot;,&#92;&quot;a0217e5e2aa5f44c&#92;&quot;,&#92;&quot;0629feeaf7920e2c&#92;&quot;,&#92;&quot;2f2a09682b0967db&#92;&quot;,&#92;&quot;fdd85c0cb9116148&#92;&quot;,&#92;&quot;2067a83f2e4cf2e1&#92;&quot;,&#92;&quot;733c2464b32ad3f6&#92;&quot;,&#92;&quot;1a8683bb29c9708d&#92;&quot;,&#92;&quot;4060d2c10f0cc6d9&#92;&quot;],&#92;&quot;x&#92;&quot;:134,&#92;&quot;y&#92;&quot;:439,&#92;&quot;w&#92;&quot;:652,&#92;&quot;h&#92;&quot;:262},{&#92;&quot;id&#92;&quot;:&#92;&quot;df36b3a29c31ce98&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;program&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a0217e5e2aa5f44c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a0217e5e2aa5f44c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e7af486f283064fa&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Program (Main)  : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0629feeaf7920e2c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;activeprog&#92;&quot;,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2f2a09682b0967db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2f2a09682b0967db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e7af486f283064fa&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Program (Active) : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fdd85c0cb9116148&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Tool_number&#92;&quot;,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2067a83f2e4cf2e1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2067a83f2e4cf2e1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e7af486f283064fa&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Tool ID : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:640,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;733c2464b32ad3f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;pallet_num&#92;&quot;,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1a8683bb29c9708d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a8683bb29c9708d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e7af486f283064fa&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Pallet ID : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:640,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4060d2c10f0cc6d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9350e391e87fe7a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;df36b3a29c31ce98&#92;&quot;,&#92;&quot;fdd85c0cb9116148&#92;&quot;,&#92;&quot;0629feeaf7920e2c&#92;&quot;,&#92;&quot;733c2464b32ad3f6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7af486f283064fa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Program &amp;amp; Tool&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;df8568c32d9e9bfa&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Position (Work)&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;db9b9d1633807788&#92;&quot;,&#92;&quot;e8b23a150120a81e&#92;&quot;,&#92;&quot;8547410491f90a0d&#92;&quot;,&#92;&quot;130dd01d8d29297f&#92;&quot;,&#92;&quot;19099f474caffd2e&#92;&quot;,&#92;&quot;2e34c68a3e9a30b2&#92;&quot;,&#92;&quot;0c375b39b14df4f1&#92;&quot;,&#92;&quot;3f61d2622a728b13&#92;&quot;,&#92;&quot;1fbf908ad8b311db&#92;&quot;,&#92;&quot;08ddb29a3ec4d7e5&#92;&quot;,&#92;&quot;69b9bad3c1781b6e&#92;&quot;],&#92;&quot;x&#92;&quot;:134,&#92;&quot;y&#92;&quot;:719,&#92;&quot;w&#92;&quot;:652,&#92;&quot;h&#92;&quot;:322},{&#92;&quot;id&#92;&quot;:&#92;&quot;db9b9d1633807788&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Xabs&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e8b23a150120a81e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e8b23a150120a81e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;X : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8547410491f90a0d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Yabs&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:820,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;130dd01d8d29297f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;130dd01d8d29297f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Y : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:820,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;19099f474caffd2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Zabs&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:880,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2e34c68a3e9a30b2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2e34c68a3e9a30b2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Z : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:880,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c375b39b14df4f1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Bpos&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3f61d2622a728b13&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3f61d2622a728b13&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;B : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1fbf908ad8b311db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mtconnect-dataitem&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;https://demo.mtconnect.org&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;5000&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dataItemId&#92;&quot;:&#92;&quot;Cpos&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:1000,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;08ddb29a3ec4d7e5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;08ddb29a3ec4d7e5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;C : &#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;26&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:1000,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;69b9bad3c1781b6e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e98fbc22244df867&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;46321a3ca1be0e85&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;db9b9d1633807788&#92;&quot;,&#92;&quot;8547410491f90a0d&#92;&quot;,&#92;&quot;19099f474caffd2e&#92;&quot;,&#92;&quot;0c375b39b14df4f1&#92;&quot;,&#92;&quot;1fbf908ad8b311db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e697761e6d26019e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Position (Work)&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;df8568c32d9e9bfa&#92;&quot;,&#92;&quot;width&#92;&quot;:6,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:4,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;7500e4ba5bb1ce02&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-solution-engine&#92;&quot;:&#92;&quot;0.9.4&#92;&quot;,&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.30.2&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow255.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-255&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mapping-mtconnect-streams/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your MTConnect dashboard is now live, pulling real-time machine data and displaying it through visual widgets. The setup you&#39;ve built here works the same way across any MTConnect-compliant machine in your facility.&lt;/p&gt;
&lt;p&gt;This is what FlowFuse does—it makes connecting to equipment, collecting data, transforming it into useful formats, and visualizing it on dashboards straightforward. Beyond basic monitoring, you can log production metrics to databases for trend analysis, set up automated alerts when machines enter fault states, integrate shop floor data with MES or ERP systems, and build event-driven workflows that respond to machine conditions. For production environments, FlowFuse Enterprise provides role-based access control, audit logging, high availability infrastructure, and dedicated support—giving you the operational controls needed to run manufacturing applications reliably across multiple facilities.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/02/mqtt-vs-coap/</id>
        <title>MQTT vs CoAP: Measure Your Constraints or Pick Wrong</title>
        <summary>The only protocol debate that matters is the one you measure.</summary>
        <updated>2026-02-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/02/mqtt-vs-coap/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The MQTT vs CoAP debate is mostly noise. One protocol assumes you have infrastructure and want centralized coordination. The other assumes you don&#39;t and can&#39;t. If you&#39;re still debating which is &amp;quot;better,&amp;quot; you haven&#39;t measured what matters.&lt;/p&gt;
&lt;p&gt;MQTT dominates because it solved the hard problem: coordinating thousands of devices through centralized brokers with persistent connections, pub/sub semantics, and delivery guarantees. CoAP survived because some deployments can&#39;t afford that solution, not as a tradeoff, but as a physical impossibility. Battery-powered sensors often can&#39;t afford long-lived TCP connections (or frequent reconnects), depending on duty cycle, radio, and power budget. Microcontrollers with 16KB RAM can&#39;t run MQTT stacks. Mesh networks at the edge can&#39;t reach brokers reliably.&lt;/p&gt;
&lt;p&gt;These aren&#39;t competing protocols. They&#39;re answers to incompatible constraints. MQTT requires infrastructure you can reach and connections you can sustain. CoAP requires neither. Pick MQTT for constrained devices, and watch batteries drain in months instead of years. Pick CoAP for cloud-coordinated fleets, and rebuild pub/sub patterns badly.&lt;/p&gt;
&lt;p&gt;This article shows what each protocol actually demands, where each fails under real constraints, and why teams consistently choose wrong, not because they pick inferior technology, but because they never validated their deployment requirements.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-separates-these-protocols&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#what-actually-separates-these-protocols&quot;&gt;What Actually Separates These Protocols&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To choose between CoAP and MQTT, you need to understand what these protocols do and what architectural assumptions they force on your system.&lt;/p&gt;
&lt;p&gt;MQTT uses a publish/subscribe model. Devices publish messages to topics. Other devices subscribe to those topics. A central broker handles routing, persistence, and delivery guarantees. This works well for many IoT scenarios: sensors broadcasting telemetry, commands flowing to actuators, aggregating data from thousands of devices into a single pipeline. The broker decouples publishers from subscribers, enabling flexible topologies and simplified client logic. But it also requires a mandatory intermediary, a single point that must be scaled, secured, and kept reliable.&lt;/p&gt;
&lt;p&gt;CoAP uses a request/response model. It mirrors HTTP&#39;s client-server architecture but strips the overhead that makes HTTP unsuitable for constrained devices. CoAP runs over UDP by default, supports multicast discovery, and operates peer-to-peer without centralized infrastructure. Resources are addressed using URIs. Clients request data. Servers respond.&lt;/p&gt;
&lt;p&gt;This isn&#39;t just a difference in wire format. It&#39;s a difference in architectural philosophy. MQTT assumes centralized coordination is beneficial. CoAP assumes it may not be necessary or even possible. That distinction shapes how these protocols behave under network failures, how they scale at the edge, and what happens when infrastructure becomes unreliable or unavailable.&lt;/p&gt;
&lt;h2 id=&quot;where-coap-has-real-advantages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#where-coap-has-real-advantages&quot;&gt;Where CoAP Has Real Advantages&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CoAP&#39;s architectural choices create measurable benefits in three specific scenarios.&lt;/p&gt;
&lt;h3 id=&quot;ultra-constrained-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#ultra-constrained-devices&quot;&gt;Ultra-Constrained Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CoAP was built for devices with severe resource limits: sensors running on coin cell batteries for years, microcontrollers with kilobytes of RAM, networks where every transmission costs energy and money. In these environments, MQTT&#39;s TCP requirement and broker dependency create overhead that isn&#39;t just inefficient, it&#39;s prohibitive.&lt;/p&gt;
&lt;p&gt;Consider the protocol overhead. An MQTT connection requires a TCP three-way handshake, then protocol negotiation. Even with minimal configuration, that&#39;s multiple round trips before any application data moves. For a sensor that wakes once per hour to send a temperature reading, this overhead destroys battery life.&lt;/p&gt;
&lt;p&gt;MQTT-SN (MQTT for Sensor Networks) attempts to bridge this gap by adapting MQTT for UDP and removing the TCP requirement. While it reduces some overhead, it still requires gateway infrastructure to translate between MQTT-SN and standard MQTT brokers, preserving the centralized architecture that CoAP avoids entirely.&lt;/p&gt;
&lt;p&gt;CoAP uses UDP, has tiny message headers (as small as 4 bytes), and operates without persistent connections. This makes it objectively more efficient. Field deployments of agricultural sensors, building automation, and environmental monitoring have demonstrated power consumption reductions of 40-60% when switching from MQTT to CoAP in ultra-constrained scenarios.&lt;/p&gt;
&lt;p&gt;The math is straightforward: fewer transmissions, smaller packets, no connection state. When your device budget is measured in microwatts and your network budget in bytes per day, CoAP is often the only viable option.&lt;/p&gt;
&lt;h3 id=&quot;edge-architectures-without-internet-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#edge-architectures-without-internet-connectivity&quot;&gt;Edge Architectures Without Internet Connectivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CoAP&#39;s advantages become more pronounced at the system level. As more processing moves to the edge for latency, bandwidth, or regulatory reasons, the value of a centralized broker decreases. Edge gateways coordinating local sensors, device-to-device communication in factories, deployments where internet connectivity is intermittent or absent, in these scenarios, CoAP&#39;s ability to work peer-to-peer without infrastructure is a genuine advantage.&lt;/p&gt;
&lt;p&gt;Consider a factory floor with hundreds of sensors and actuators coordinating through a local gateway. With MQTT, every sensor-to-actuator interaction must route through the broker, even when both devices are physically adjacent. The broker becomes a mandatory hop, adding latency and creating a single point of failure.&lt;/p&gt;
&lt;p&gt;With CoAP, devices communicate directly. The gateway can still aggregate and forward data to the cloud when needed, but local control loops operate independently. When the internet connection drops, local operations continue. When latency matters, safety interlocks in industrial equipment, eliminating the broker hop can mean the difference between meeting requirements and failing them.&lt;/p&gt;
&lt;p&gt;This distinction matters even more in mobile or disconnected scenarios: autonomous vehicles coordinating with roadside infrastructure, offshore platforms where satellite bandwidth is expensive, emergency networks operating with degraded connectivity.&lt;/p&gt;
&lt;h3 id=&quot;integration-with-web-infrastructure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#integration-with-web-infrastructure&quot;&gt;Integration with Web Infrastructure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When distributed systems need to communicate with backend infrastructure, CoAP offers another benefit: it aligns with web semantics. CoAP deliberately mirrors HTTP: URIs, methods (GET, POST, PUT, DELETE), content negotiation, status codes. This means it integrates naturally with RESTful systems, web proxies, and developer tools built around HTTP.&lt;/p&gt;
&lt;p&gt;For organizations already using REST APIs, CoAP presents a lower barrier than MQTT&#39;s topic-based model. HTTP-to-CoAP proxies are straightforward because the semantic models align. MQTT-to-HTTP bridges require significant translation. Topics must map to endpoints. QoS semantics must adapt. Pub/sub patterns must be forced into request/response or require additional infrastructure like webhooks.&lt;/p&gt;
&lt;p&gt;None of this is impossible. Organizations bridge MQTT and HTTP successfully every day. But the mismatch is real and introduces complexity that CoAP avoids by design.&lt;/p&gt;
&lt;h2 id=&quot;where-mqtt-still-dominates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#where-mqtt-still-dominates&quot;&gt;Where MQTT Still Dominates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These CoAP advantages are real. But if we stop here, we miss the bigger picture. MQTT isn&#39;t being displaced, and the reason goes deeper than momentum. In most production IoT deployments, MQTT&#39;s architectural choices aren&#39;t limitations, they&#39;re features that solve problems CoAP cannot.&lt;/p&gt;
&lt;h3 id=&quot;publisher%2Fsubscriber-decoupling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#publisher%2Fsubscriber-decoupling&quot;&gt;Publisher/Subscriber Decoupling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The pub/sub model is a fundamental decoupling mechanism that enables capabilities difficult or impossible with request/response.&lt;/p&gt;
&lt;p&gt;Consider industrial telemetry. Thousands of sensors publishing measurements. Multiple backend systems consuming that data: a time-series database for analysis, a rules engine for alerts, a machine learning pipeline for predictive maintenance, a dashboard for operators.&lt;/p&gt;
&lt;p&gt;With MQTT, adding a new consumer is trivial. Subscribe to the topics. The sensors don&#39;t know you exist. They don&#39;t need reconfiguration or firmware updates. The decoupling is complete.&lt;/p&gt;
&lt;p&gt;With CoAP, this becomes complex. If sensors are servers, how do new clients discover them? If sensors are clients pushing data, where do they push? How do you add a destination without reconfiguring every device? You end up rebuilding what a broker provides, service discovery, routing, fan-out, but distributed across your device fleet instead of centralized in infrastructure you control.&lt;/p&gt;
&lt;p&gt;This is why MQTT dominates cloud ingestion. When your architecture is about collecting data from many devices and distributing it to many consumers, the broker model is the right abstraction.&lt;/p&gt;
&lt;h3 id=&quot;delivery-guarantees&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#delivery-guarantees&quot;&gt;Delivery Guarantees&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The broker provides something CoAP struggles to match: robust delivery guarantees across unreliable networks.&lt;/p&gt;
&lt;p&gt;MQTT&#39;s three QoS levels (at most once, at least once, exactly once) are fundamental guarantees many production systems require. CoAP, being UDP-based, offers optional confirmable messages with retransmission. This works for many scenarios, but it&#39;s not equivalent to MQTT&#39;s QoS 2 (exactly once delivery). If your application cannot tolerate duplicates, financial transactions, command-and-control, state machine updates, MQTT&#39;s exactly-once semantics are non-negotiable.&lt;/p&gt;
&lt;p&gt;MQTT&#39;s QoS guarantees are end-to-end through the broker. Messages can persist to disk. Sessions resume after disconnection. Client state is maintained. This makes MQTT significantly more resilient to network instability and device mobility.&lt;/p&gt;
&lt;h3 id=&quot;ecosystem-maturity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#ecosystem-maturity&quot;&gt;Ecosystem Maturity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These technical advantages are amplified by years of real-world deployment and community investment. MQTT has battle-tested brokers (Mosquitto, EMQX, HiveMQ, VerneMQ). Comprehensive client libraries in every language. Integration with major IoT platforms (AWS IoT Core, Azure IoT Hub) and widely used broker/vendor ecosystems. Monitoring tools, debugging utilities, best practices, and a large community that has solved common problems.&lt;/p&gt;
&lt;p&gt;CoAP has matured significantly, but its ecosystem is smaller. This reflects where the use cases are. Cloud ingestion, telemetry aggregation, command and control, these patterns dominate IoT. CoAP&#39;s narrower focus on ultra-constrained devices and peer-to-peer edge scenarios means fewer developers encounter it, fewer tools get built, fewer problems get solved publicly.&lt;/p&gt;
&lt;p&gt;Network effects matter. When MQTT is the default, more effort improves MQTT tooling, which makes MQTT more attractive, which reinforces its position.&lt;/p&gt;
&lt;h3 id=&quot;session-state-and-message-queuing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#session-state-and-message-queuing&quot;&gt;Session State and Message Queuing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT provides another capability CoAP implementers often underestimate: stateful session management.&lt;/p&gt;
&lt;p&gt;MQTT&#39;s persistent sessions enable offline message queuing. If a device disconnects, battery dies, network drops, enters a tunnel, messages published to its subscribed topics get queued by the broker and delivered when it reconnects. This is invaluable for mobile devices, intermittently connected sensors, and scenarios where guaranteed delivery matters more than real-time delivery. Examples include fleet management tracking vehicles, medical devices uploading telemetry, and remote monitoring in areas with poor connectivity.&lt;/p&gt;
&lt;p&gt;CoAP can implement message queuing, but it requires additional infrastructure, essentially building broker-like services for state management and persistence. At which point, you&#39;ve rebuilt the pattern MQTT provides natively.&lt;/p&gt;
&lt;h2 id=&quot;security%3A-choose-based-on-what-you-can-measure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#security%3A-choose-based-on-what-you-can-measure&quot;&gt;Security: Choose Based on What You Can Measure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT and CoAP impose fundamentally different security architectures. MQTT&#39;s broker creates a centralized security choke point with TLS-protected connections, certificate-based authentication, and topic-level authorization. This simplifies policy enforcement and audit trails but introduces measurable overhead, a TLS handshake consumes 30-50% of total power for sensors transmitting hourly, prohibitive for ultra-constrained devices where battery life is measured in years.&lt;/p&gt;
&lt;p&gt;CoAP distributes security across peer-to-peer networks. DTLS provides encrypted UDP communication with similar handshake costs to TLS. For constrained deployments, OSCORE enables application-layer security without connection establishment, reducing wake time by 60-80%. But this efficiency trades centralized control for distributed key management complexity that scales poorly without additional infrastructure.&lt;/p&gt;
&lt;p&gt;The architectural trade-off is concrete: MQTT centralizes authentication and policy enforcement but requires broker infrastructure with power overhead. CoAP eliminates broker dependency but pushes authorization to individual devices, requiring distributed policy updates and log aggregation.&lt;/p&gt;
&lt;p&gt;The most common security failure is choosing based on perceived simplicity rather than measured requirements. Teams select MQTT assuming TLS is well understood, then discover field batteries depleting in weeks. Teams choose CoAP to avoid broker dependency, then realize they cannot revoke compromised credentials without manual intervention across distributed devices.&lt;/p&gt;
&lt;p&gt;Before choosing, measure connection establishment cost in actual power consumption for your device profile, operational cost of key management at your projected scale, and whether your compliance requirements favor centralized audit trails or distributed authorization. The right security model is the one that matches the operational reality you can actually sustain.&lt;/p&gt;
&lt;h2 id=&quot;the-measurement-discipline-that-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/02/mqtt-vs-coap/#the-measurement-discipline-that-matters&quot;&gt;The Measurement Discipline That Matters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What separates successful deployments from failed ones isn&#39;t choosing the &amp;quot;better&amp;quot; protocol. It&#39;s starting with measured constraints rather than architectural preferences.&lt;/p&gt;
&lt;p&gt;The teams that ship working systems know their sensor consumes 12 microamps in sleep and 45 milliamps during transmission. A CR2032 battery provides 235 milliamp-hours. For three-year operation, the math reveals a daily transmission budget of roughly 200 messages. Protocol overhead becomes concrete. Connection establishment costs aren&#39;t theoretical, they determine whether you meet requirements or miss by months.&lt;/p&gt;
&lt;p&gt;Teams that struggle start with vague requirements. &amp;quot;Low power&amp;quot; sounds reasonable until batteries die early in field trials. &amp;quot;Real-time&amp;quot; invites endless debate until you specify &amp;quot;actuator response within 50 milliseconds for 99% of events.&amp;quot; Precision transforms discussion into engineering.&lt;/p&gt;
&lt;p&gt;If you need to decouple thousands of publishers from dozens of consumers with guaranteed delivery across unreliable networks, MQTT&#39;s broker model provides exactly that. The centralized architecture handles message routing, persistence, and quality of service.&lt;/p&gt;
&lt;p&gt;If your constraint is battery operation where every transmission costs operational lifetime, and infrastructure cannot be deployed reliably, CoAP&#39;s lightweight UDP approach becomes necessary. TCP overhead and broker coordination would exceed your power budget.&lt;/p&gt;
&lt;p&gt;If your system genuinely spans both contexts, use both protocols where each fits. The constraints will make this obvious.&lt;/p&gt;
&lt;p&gt;Most failed projects share a common pattern. They selected protocols before measuring deployment reality. They assumed requirements without validation. They copied architectures without understanding the underlying trade-offs. Then field deployment revealed the gaps.&lt;/p&gt;
&lt;p&gt;So before choosing between MQTT and CoAP, answer these with measured data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is your power budget per device?&lt;/li&gt;
&lt;li&gt;What transmission frequency and payload size does your application require?&lt;/li&gt;
&lt;li&gt;How does latency behave under network degradation?&lt;/li&gt;
&lt;li&gt;During partitions, can operations continue locally or must activity queue?&lt;/li&gt;
&lt;li&gt;What do infrastructure costs look like at production scale?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you cannot answer with measurements, build a prototype. Instrument it. Run it under realistic conditions. Measure power, latency, and costs under stress. Then choose based on evidence, not assumptions.&lt;/p&gt;
&lt;p&gt;The protocol debate becomes irrelevant once you measure. MQTT and CoAP each solve distinct problems well. Understand your constraints, and the choice becomes clear.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/</id>
        <title>Agentic AI Reads OPC UA Servers So You Don&#39;t Have To</title>
        <summary>Why manual OPC UA investigation is the bottleneck, and how agentic AI eliminates it</summary>
        <updated>2026-01-30T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;OPC UA servers store everything. Finding anything takes hours.&lt;/p&gt;
&lt;p&gt;Your historian has six months of production data across 847 variables. Wednesday&#39;s batch failed quality checks. The root cause is in there—a sensor drift, a temperature anomaly, something that happened before the failure became visible. But variables are named &lt;code&gt;ns=2;s=Device1.PLC.DB1.Temp_Sensor_3&lt;/code&gt;. The namespace structure was designed for PLC efficiency, not human investigation.&lt;/p&gt;
&lt;p&gt;So you click through hierarchies. Cross-reference documentation that&#39;s two firmware versions out of date. Export data to Excel. Build correlation matrices. Check timing against process logs. Four hours later, you find it.&lt;/p&gt;
&lt;p&gt;OPC UA gave machines a common language. It solved connectivity. But it created an accessibility problem: the data infrastructure that captures everything makes finding specific answers remarkably slow.&lt;/p&gt;
&lt;p&gt;The solution isn&#39;t better visualization or more dashboards. It&#39;s removing humans from the navigation process entirely. AI agents can browse OPC UA servers, pull historian data, run correlations, and surface answers while you&#39;re still typing the question.&lt;/p&gt;
&lt;h1 id=&quot;why-investigation-remains-the-bottleneck&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/#why-investigation-remains-the-bottleneck&quot;&gt;Why Investigation Remains the Bottleneck&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Implementation problems in industrial IoT are largely solved. Teams connect devices, configure historians, and establish data flows with impressive efficiency, especially on platforms like FlowFuse. The wheels fall off when someone actually needs to &lt;em&gt;use&lt;/em&gt; that data.&lt;/p&gt;
&lt;p&gt;Your monitoring dashboard flags a reject rate spike on Line 3. That&#39;s the easy part—alerts work. But dashboards show you &lt;em&gt;symptoms&lt;/em&gt;, not &lt;em&gt;causes&lt;/em&gt;. Finding the cause means reconstructing what happened in the hours leading up to the spike. Which of the seventy-three variables on Line 3 changed? What correlations exist between the temperature sensors and quality metrics? How does this week&#39;s pattern compare to normal operations?&lt;/p&gt;
&lt;p&gt;Every operational question follows this pattern. Why did energy consumption spike Tuesday? Which sensor readings predict motor failures? What operating conditions maximize packaging throughput? The questions change. The investigative workflow doesn&#39;t—navigate namespaces, extract data, analyze patterns, interpret results. Manual. Every. Single. Time.&lt;/p&gt;
&lt;p&gt;Here&#39;s what makes this a systemic crisis rather than an annoyance: the data exists. The infrastructure works. But converting data into operational intelligence requires hours of skilled labor &lt;em&gt;per question&lt;/em&gt;. So people stop asking questions. They stick to pre-configured dashboards showing metrics someone decided to monitor six months ago. They don&#39;t explore. They don&#39;t investigate unexpected patterns. They definitely don&#39;t do the kind of exploratory analysis that actually drives improvement.&lt;/p&gt;
&lt;p&gt;The standard solutions miss the fundamental problem. Hiring more analysts scales linearly at best—you get three people doing manual work instead of one. Building more dashboards only helps when you already know what to monitor. Neither solves for the unexpected question, the one-off investigation, the &amp;quot;something doesn&#39;t look right&amp;quot; hunch that requires pulling data you&#39;ve never looked at before.&lt;/p&gt;
&lt;h2 id=&quot;what-ai-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/#what-ai-changes&quot;&gt;What AI Changes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The value proposition is straightforward: Replace manual investigation workflows with automated execution.&lt;/p&gt;
&lt;p&gt;Thursday afternoon, Line 3&#39;s reject rate spikes. The traditional approach takes six hours minimum if the data&#39;s clean and you know exactly where to look: Pull historian data for fifty variables that might matter. Build correlation matrices in Excel. Analyze sensor drift patterns. Cross-reference timing against process logs. Compare current performance against last month&#39;s baseline. Pull in a colleague to verify you didn&#39;t miss something obvious.&lt;/p&gt;
&lt;p&gt;Ask an AI agent: &lt;em&gt;&amp;quot;What changed in Line 3 before Thursday&#39;s spike?&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The agent queries your historian across relevant subsystems. Runs timing correlations against the reject rate increase. Identifies statistical anomalies in sensor data. Tests relationships between variables. Flags causation with confidence intervals. Five minutes later you&#39;re reviewing root cause analysis, not building it from scratch.&lt;/p&gt;
&lt;p&gt;This efficiency compounds across every investigative use case:&lt;/p&gt;
&lt;p&gt;Predictive analysis that would take weeks becomes instant queries. Understanding how motor current relates to product quality typically requires extracting time-series data from your historian, cleaning datasets, running statistical tests, validating correlations, interpreting significance—three months of dedicated work. The agent returns correlation matrices with confidence intervals and outlier analysis while you&#39;re finishing your coffee.&lt;/p&gt;
&lt;p&gt;Compliance documentation that takes weeks to compile generates on demand. Audits need complete OPC UA server documentation—node hierarchies, relationship mappings, system architecture, operational ranges calculated from historical performance. Manually, that&#39;s weeks of browsing address spaces and organizing specifications. The agent generates it directly from live server metadata and your historical data. Infrastructure changes next quarter? Regenerate the documentation instead of manually updating deprecated specs.&lt;/p&gt;
&lt;p&gt;Pattern recognition at scale becomes feasible. Agents analyze patterns across days, weeks, months of continuous operation—patterns humans miss because they require simultaneous analysis of thousands of variables. &amp;quot;Show me every instance where Variable_A spiked within ten minutes of Variable_B changing&amp;quot; becomes a query you actually ask instead of a question you abandon because the manual investigation would take too long.&lt;/p&gt;
&lt;p&gt;The mechanical work executes automatically: namespace navigation, data retrieval, correlation testing, anomaly detection. Your time goes to what requires actual judgment—interpreting analytical findings against operational knowledge, deciding whether to adjust processes or schedule maintenance. Questions you&#39;d previously skip because investigation overhead exceeded potential value become queries worth asking.&lt;/p&gt;
&lt;h2 id=&quot;the-technology-behind-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/#the-technology-behind-it&quot;&gt;The Technology Behind It&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse makes this work through a straightforward architectural approach that connects AI reasoning to industrial data systems.&lt;/p&gt;
&lt;p&gt;As an industrial data platform, FlowFuse already handles connectivity to OPC UA servers, historians, and other industrial systems. The new capability comes from MCP nodes that expose this connectivity through the Model Context Protocol—a standardized interface that lets AI systems interact with any data source using common operations like browse, read, query, and analyze.&lt;/p&gt;
&lt;p&gt;Here&#39;s how it flows: You ask your AI agent a question in natural language. The agent translates that into MCP operations—browse this namespace, retrieve these variables, analyze this time range. FlowFuse receives those operations and executes them against your actual infrastructure, handling all the OPC UA protocol complexity, session management, and security. The agent gets back structured data, interprets it, and gives you an answer.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;High-level architecture diagram showing the interaction between Al agents and industrial systems via the FlowFuse Platform.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ai-mcp-opcua.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;High-level architecture diagram showing the interaction between Al agents and industrial systems via the FlowFuse Platform.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The architecture separates concerns cleanly. AI handles the reasoning—figuring out what data matters and how to interpret it. FlowFuse handles the execution—dealing with industrial protocols, data access, and system integration. Neither tries to do the other&#39;s job.&lt;/p&gt;
&lt;p&gt;For teams building their own integrations, the implementation details are documented here: &lt;a href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/&quot;&gt;Building MCP Server Using FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Watch It Work&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The video below shows an AI agent generating complete OPC UA server documentation on request—finishing in minutes what typically requires weeks of manual effort.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;agxAw4B91Nw&quot; style=&quot;width: 1024px; overflow: hidden; background-image: url(&#39;/blog/2026/01/images/ai-opcua-document-generation.jpg&#39;); background-size: cover; background-position: center;&quot; title=&quot;AI Agent Generating OPC UA Documentation&quot;&gt;
&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-this-unlocks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/#what-this-unlocks&quot;&gt;What This Unlocks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Connecting agents to OPC UA infrastructure delivers capabilities manual investigation can&#39;t match at scale.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Autonomous navigation across address spaces.&lt;/strong&gt; Agents read node hierarchies, examine metadata—DisplayNames, EngineeringUnits, data types, access levels—follow references between nodes, build structural understanding of systems. You describe what you need, agent locates relevant nodes. No memorizing namespace paths or node IDs. Looking for a pump&#39;s discharge pressure sensor buried five levels deep in your hierarchy? Agent finds it by understanding equipment relationships, not because someone documented the exact path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated data analysis across historians.&lt;/strong&gt; Agents pull historical data, run statistical tests, calculate correlations, detect anomalies, compare time periods, validate significance. Ask &amp;quot;How does ambient temperature affect motor current draw on Line 2?&amp;quot; and get months of historian data analyzed—variables correlated, confounding factors accounted for, confidence intervals calculated. Manual approach means days of Excel work: extraction, cleaning, statistical analysis, validation. Agent returns analyzed results in minutes while you&#39;re still drinking your coffee.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pattern recognition at operational scale.&lt;/strong&gt; Agents analyze patterns across days, weeks, months of continuous operation—patterns humans miss because they require simultaneous analysis of thousands of variables. &amp;quot;Show me every instance where Variable_A spiked within ten minutes of Variable_B changing&amp;quot; becomes a query you actually ask instead of a question you abandon. Finding subtle leading indicators of equipment degradation across hundreds of sensors? Agent correlates every variable combination, identifies statistically significant patterns, surfaces predictions. Doing this manually would take months of dedicated work. Nobody attempts it because nobody has months to spare.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Investigation capabilities that previously required dedicated data science teams become natural language queries. Complex analyses finish in minutes instead of weeks. Questions you&#39;d skip because the investigation wasn&#39;t worth the effort become routine operational intelligence you actually use.&lt;/p&gt;
&lt;h2 id=&quot;the-bigger-picture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/eliminate-opc-ua-bottleneck-ai-agents/#the-bigger-picture&quot;&gt;The Bigger Picture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The value in industrial data was never about collection—it was always about the questions that data could answer. Those questions just cost too much time to pursue. When investigation drops from hours to minutes, the economics change completely. Different questions become worth asking. Documentation stays current because updating it is on-demand instead of weeks of work. Pattern analysis across thousands of variables becomes routine instead of heroic.&lt;/p&gt;
&lt;p&gt;This isn&#39;t about replacing people with automation. It&#39;s about making the data infrastructure you already built actually useful for the decisions it was meant to inform. Your team still interprets results, makes judgment calls, and takes action. The AI just handles the mechanical work of data access and analysis.&lt;/p&gt;
&lt;p&gt;And it&#39;s not limited to OPC UA. FlowFuse&#39;s MCP approach works the same way across any industrial system—MQTT brokers, Modbus devices, SQL databases, REST APIs, whatever protocols you&#39;re running. Same natural language interface, same investigation capabilities, different underlying systems. The infrastructure you have becomes the infrastructure you can actually use.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/why-modbus-still-exist/</id>
        <title>Why Modbus Refuses to Die</title>
        <summary>Why your factory&#39;s newest equipment still speaks a 47-year-old language</summary>
        <updated>2026-01-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/why-modbus-still-exist/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Modbus is 47 years old and has no built-in security. By every measure, it should have been obsolete a decade ago. OPC UA, EtherNet/IP, MQTT, Profinet: modern protocols with semantic modeling, encryption, and real-time capabilities arrived backed by billions in vendor investment and industry standardization efforts.&lt;/p&gt;
&lt;p&gt;Yet in 2026, new equipment still ships with Modbus as the primary interface. Not tucked away for backward compatibility, but front and center as the deliberate first choice.&lt;/p&gt;
&lt;p&gt;What&#39;s keeping a protocol from 1979 alive when everything about industrial automation has changed?&lt;/p&gt;
&lt;h2 id=&quot;the-installed-base-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#the-installed-base-reality&quot;&gt;The Installed Base Reality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturing facilities don&#39;t replace working automation systems. They just don&#39;t. A plant manager looks at a control panel full of PLCs and motor drives from 2005, all communicating via Modbus, all running production smoothly, and the conversation ends there. Finance already depreciated that equipment over fifteen years. Maintenance has spare parts stocked. Operators know how to troubleshoot it. Why would anyone rip that out?&lt;/p&gt;
&lt;p&gt;The equipment wasn&#39;t designed for short lifecycles. &lt;a href=&quot;https://www.indmall.in/faq/how-long-do-plc-components-typically-last/&quot;&gt;Industrial PLCs typically last around 10 to 20 years&lt;/a&gt; depending on environment and maintenance. Process industry equipment like pumps, transmitters, and valves often &lt;a href=&quot;https://www.automationworld.com/products/control/article/13311314/plc-lifecycle-management&quot;&gt;hits 20-30 years before replacement becomes necessary&lt;/a&gt;. &lt;a href=&quot;https://www.manufacturing.net/operations/article/13057130/is-the-united-states-ready-to-take-manufacturing-back&quot;&gt;The average age of manufacturing equipment in the US is close to 20 years, and since 1990, the age of assets has virtually doubled&lt;/a&gt;. Not because companies can&#39;t afford upgrades. Because the equipment still works.&lt;/p&gt;
&lt;p&gt;That creates a problem for protocol modernization. You can&#39;t swap out a few devices at a time. Industrial networks are interconnected systems where everything talks to everything else. Upgrading means either taking down the entire line for a coordinated replacement, or maintaining parallel communication infrastructure during a phased migration. Both options are expensive, risky, and deliver zero production benefit.&lt;/p&gt;
&lt;p&gt;The numbers show how big this problem is. &lt;a href=&quot;https://www.futuremarketreport.com/industry-report/modbus-communication-module-market&quot;&gt;The Modbus TCP market alone was $1.35 billion in 2024, projected to hit $2.55 billion by 2032&lt;/a&gt;. That&#39;s not legacy support. That&#39;s active growth. Companies are buying new Modbus devices in 2026 to integrate with Modbus networks from 2006.&lt;/p&gt;
&lt;h2 id=&quot;it-costs-almost-nothing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#it-costs-almost-nothing&quot;&gt;It Costs Almost Nothing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The economics of Modbus implementation are absurdly compelling. A basic Modbus RTU interface costs manufacturers maybe $5-10 in components. Software licensing? Zero. The protocol is completely open, no royalties, no certification fees, no vendor lock-in. Compare that to implementing industrial Ethernet protocols where you might pay thousands for stack licenses, certification processes, and conformance testing.&lt;/p&gt;
&lt;p&gt;For device manufacturers, this matters enormously. A sensor company can add Modbus support for trivial cost and immediately become compatible with millions of existing installations. The development effort is minimal: the protocol specification fits in a few dozen pages, implementations are straightforward, and countless reference designs exist. You don&#39;t need specialized silicon or complex firmware. A basic microcontroller with a UART can speak Modbus RTU. Add an Ethernet chip and you&#39;ve got Modbus TCP.&lt;/p&gt;
&lt;p&gt;This simplicity extends through the entire supply chain. Integrators don&#39;t need expensive training or specialized tools. A laptop, some free software, and basic understanding of serial communication gets you started. Troubleshooting requires nothing more sophisticated than a protocol analyzer, or in many cases, just watching register values change. The barrier to entry is so low that maintenance technicians can learn Modbus basics in an afternoon.&lt;/p&gt;
&lt;p&gt;The contrast with modern protocols is stark. OPC UA requires understanding information modeling, certificate management, and complex security configurations. Profinet demands precise timing requirements and specialized hardware. EtherCAT needs real-time capable network controllers. Each adds cost, complexity, and dependencies. Each creates opportunities for things to go wrong.&lt;/p&gt;
&lt;h2 id=&quot;the-vendor-neutral-advantage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#the-vendor-neutral-advantage&quot;&gt;The Vendor-Neutral Advantage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Perhaps Modbus&#39;s greatest strength is that nobody owns it. Modicon created it in 1979, but the rights now belong to the Modbus Organization, a trade association that maintains the specification as an open standard. This means no single vendor can kill it, paywall it, or steer it toward proprietary extensions.&lt;/p&gt;
&lt;p&gt;Industrial automation is full of protocol wars where vendors push their preferred standards. Rockwell champions EtherNet/IP. Siemens invested heavily in Profinet. Every major automation vendor has protocols they&#39;d rather you use: protocols that tie you into their ecosystem, their training programs, their support contracts.&lt;/p&gt;
&lt;p&gt;Modbus doesn&#39;t care. It works with everyone&#39;s equipment. This vendor neutrality has enormous practical value in facilities running mixed automation systems. A typical factory floor might have Rockwell PLCs, ABB drives, Schneider Electric power meters, and Siemens HMIs all talking to each other. Getting all those vendors&#39; preferred protocols to coexist would be a nightmare. Getting them all to speak Modbus is trivial.&lt;/p&gt;
&lt;p&gt;This creates competitive pressure that keeps Modbus relevant. Device manufacturers can&#39;t afford to skip Modbus support because doing so immediately excludes them from projects with heterogeneous automation systems. Even vendors with their own sophisticated protocols implement Modbus as a fallback, ensuring interoperability when nothing else works.&lt;/p&gt;
&lt;p&gt;The open nature also prevents the protocol from becoming a competitive weapon. Nobody can leverage Modbus to lock customers into their platform. Nobody can obsolete older Modbus devices by dropping support in newer products. The protocol&#39;s longevity is guaranteed by the fact that no single entity controls its fate.&lt;/p&gt;
&lt;h2 id=&quot;the-technical-case-for-modbus&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#the-technical-case-for-modbus&quot;&gt;The Technical Case for Modbus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond the strategic and economic reasons, Modbus delivers real technical advantages that matter when you&#39;re building and maintaining industrial systems:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Brutally simple operation.&lt;/strong&gt; Modbus does exactly one thing: it reads and writes registers. No object models, no service-oriented architecture, no semantic layers. Just addresses and values. When a motor drive fails at 3 AM, the maintenance technician doesn&#39;t want to debug XML schemas or navigate object hierarchies. They want to see if register 40001 is returning the right value. The diagnostic process is straightforward: Can you communicate? Are you reading the right address? Is the value correct? Done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Predictable and lightweight.&lt;/strong&gt; Modbus frames are small: RTU maxes out at 256 bytes, TCP at 260 bytes. The protocol data unit itself can&#39;t exceed 253 bytes. This minimal overhead works fine on 9600 baud serial links still common in older facilities. No state to manage, no synchronized clocks, no microsecond timing requirements like industrial Ethernet protocols demand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trivial to implement.&lt;/strong&gt; A basic Modbus stack runs on 8-bit microcontrollers with as little as 10KB flash and 1.5KB RAM. On a PIC16F1827 with 7KB program memory and 384 bytes of data RAM, a complete Modbus RTU implementation uses roughly a quarter of total resources. The entire protocol specification runs maybe 150 pages total. A competent embedded developer can knock out a working implementation in days, not months.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debugging is transparent.&lt;/strong&gt; Register 40001 is register 40001, period. Hook up a protocol analyzer and you see the raw data: device address, function code, register address, value, CRC. No security? That&#39;s one less thing to troubleshoot. No discovery mechanism? That&#39;s fine, you configured the addresses once during commissioning and they never change. No data typing beyond basic registers? Perfectly adequate when you know a particular register holds temperature in tenths of degrees Celsius.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Universal compatibility.&lt;/strong&gt; Same protocol on RS-485, RS-232, TCP/IP, even UDP. Modbus devices are addressed from 1 to 247 on serial networks. Converting between Modbus RTU and Modbus TCP is trivial: cheap gateway boxes handle it automatically. You can broadcast to all devices using address 0 for synchronized updates. Modbus devices from different manufacturers actually interoperate. Not in theory, in practice. A Modbus master from Company A will communicate with a Modbus slave from Company B without negotiation, configuration wizards, or integration consultants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fast enough for most applications.&lt;/strong&gt; Typical Modbus response time is under 10 milliseconds for 90% of exchanges, though it can occasionally stretch to 150ms depending on device processing. That&#39;s plenty fast for process control, monitoring, and most industrial automation tasks. Not fast enough for coordinated motion control, but that&#39;s not what Modbus was designed for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reliable error detection.&lt;/strong&gt; Modbus RTU uses CRC-16-MODBUS for error checking. Modbus ASCII uses longitudinal redundancy check (LRC). Modbus TCP relies on TCP&#39;s built-in data integrity. Each message is independent: no session state means no state corruption. Simple design means fewer things break when a sensor sits in a 60°C cabinet or -20°C freezer for twenty years.&lt;/p&gt;
&lt;p&gt;These technical advantages translate directly to faster development cycles, simpler troubleshooting, lower hardware costs, and more reliable operation in harsh industrial conditions where complex protocols would create more failure points.&lt;/p&gt;
&lt;h2 id=&quot;when-modern-protocols-actually-win&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#when-modern-protocols-actually-win&quot;&gt;When Modern Protocols Actually Win&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus&#39;s strengths become liabilities when you need capabilities beyond simple register polling. There are entire classes of industrial applications where choosing Modbus means accepting fundamental limitations that modern protocols solve elegantly.&lt;/p&gt;
&lt;p&gt;Try running a multi-axis CNC machine or coordinated robot cell over Modbus and you&#39;ll understand why EtherCAT exists. Modbus operates on a poll-response cycle: the master asks, the slave answers, repeat. At 115.2 kbaud, you&#39;re looking at 25-50 milliseconds per device minimum.&lt;/p&gt;
&lt;p&gt;Stack up ten servo drives that need position updates synchronized within microseconds, and Modbus simply cannot deliver. EtherCAT, Profinet IRT, and SERCOS III provide deterministic cycle times under 1 millisecond with jitter measured in nanoseconds. This isn&#39;t a performance difference, it&#39;s a capability gap. Motion applications requiring sub-millisecond synchronization across multiple axes have no choice but to use these specialized protocols.&lt;/p&gt;
&lt;p&gt;Modbus gives you registers. That&#39;s it. Register 40023 could be motor temperature, error flags, or the number of production cycles: you only know because someone documented it somewhere. Scale this to a facility with thousands of data points across hundreds of devices and the maintenance burden becomes crushing.&lt;/p&gt;
&lt;p&gt;OPC UA solves this with information modeling that makes data self-describing. A temperature sensor doesn&#39;t just expose a value, it exposes metadata about units, range, accuracy, and context. When you&#39;re building systems that need to automatically discover capabilities, validate configurations, or provide rich &lt;a href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/&quot;&gt;HMI&lt;/a&gt; experiences, OPC UA&#39;s semantic layer isn&#39;t optional overhead: it&#39;s the foundation that makes complexity manageable.&lt;/p&gt;
&lt;p&gt;For decades, industrial networks lived behind air gaps and Modbus&#39;s lack of authentication didn&#39;t matter. Those days are over. Modern facilities need remote monitoring, cloud analytics, vendor support access, and integration with enterprise IT systems.&lt;/p&gt;
&lt;p&gt;The moment you connect to external networks, Modbus&#39;s plaintext communication and zero authentication become indefensible. An attacker with network access can send arbitrary commands to any Modbus device. No password, no certificate, no audit trail.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;OPC UA&lt;/a&gt; provides TLS encryption, certificate-based authentication, role-based access control, and detailed audit logging. &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; with &lt;a href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/&quot;&gt;Sparkplug B&lt;/a&gt; adds lightweight security for IIoT deployments. These aren&#39;t nice-to-have features when you&#39;re connecting critical infrastructure to the internet: they&#39;re requirements. Companies implementing Industry 4.0 initiatives, remote operations, or cloud-based analytics cannot build on &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Modbus&lt;/a&gt;. The protocol has no security model to extend.&lt;/p&gt;
&lt;p&gt;Modbus RTU at 115.2 kbaud can theoretically handle around 80-100 transactions per second under ideal conditions, but real-world installations see more like 40-60 due to device processing time and network overhead. That&#39;s fine for a few dozen devices with slow-changing process variables.&lt;/p&gt;
&lt;p&gt;It collapses when you need high-resolution data from hundreds of sensors. Environmental monitoring systems, vibration analysis, or energy metering across large facilities quickly saturate Modbus networks. Even Modbus TCP, while faster, lacks the bandwidth efficiency of modern protocols.&lt;/p&gt;
&lt;p&gt;MQTT&#39;s publish-subscribe model eliminates polling overhead entirely. Profinet and &lt;a href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/&quot;&gt;EtherNet/IP&lt;/a&gt; use producer-consumer architectures that scale better. When data volume grows beyond simple polling scenarios, Modbus becomes the bottleneck.&lt;/p&gt;
&lt;p&gt;If you&#39;re building a new plant from scratch with modern equipment and no legacy constraints, defaulting to Modbus is choosing 1979 technology for 2026 problems. You lose semantic modeling, security, diagnostic capabilities, and future-proofing.&lt;/p&gt;
&lt;p&gt;The cost argument weakens too: modern industrial Ethernet switches and device interfaces aren&#39;t dramatically more expensive than RS-485 infrastructure when you factor in reduced wiring labor. The real question is whether you&#39;re building for today&#39;s requirements or tomorrow&#39;s.&lt;/p&gt;
&lt;p&gt;Modbus works great until you need asset monitoring, predictive maintenance, cloud integration, or advanced analytics. Then you&#39;re ripping out infrastructure you just installed.&lt;/p&gt;
&lt;p&gt;Modbus TCP added IP networking but fundamentally remained a register-based polling protocol. There&#39;s no roadmap for features industrial facilities increasingly need: time synchronization, alarm management, historical data access, file transfer, or complex data types.&lt;/p&gt;
&lt;p&gt;Modern protocols continue evolving. OPC UA added pub-sub models, field-level communications, and TSN integration. The Modbus specification is essentially frozen because any significant changes would break the simplicity that makes it useful. This works fine in stable applications but becomes a ceiling when operational needs expand beyond what the protocol was designed for forty-six years ago.&lt;/p&gt;
&lt;h2 id=&quot;the-hybrid-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/why-modbus-still-exist/#the-hybrid-reality&quot;&gt;The Hybrid Reality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The industry has settled on a hybrid reality that favors encapsulation over replacement. Edge gateways now act as the primary translators, speaking Modbus to legacy hardware while providing secure MQTT or OPC UA feeds to the cloud. This allows maintenance teams to keep their reliable hardware while IT departments receive the structured, authenticated data they require for modern analytics.&lt;/p&gt;
&lt;p&gt;Network segmentation becomes the security strategy. Critical Modbus networks stay isolated from the internet. Remote access happens through VPNs and jump boxes. Protocol gateways enforce security boundaries. It&#39;s more complex than native security in modern protocols, but it works with equipment that was never designed for network security in the first place.&lt;/p&gt;
&lt;p&gt;The result is a patchwork that reflects industrial reality rather than protocol purity. Modbus handles what it does well: simple, reliable communication with field devices. Modern protocols handle what Modbus can&#39;t: semantic data, security, cloud integration. The two worlds coexist because forcing a single protocol across all applications would be both technically limiting and economically wasteful.&lt;/p&gt;
&lt;p&gt;This approach proves that Modbus survives not because it&#39;s technically superior, but because it solves real problems with minimal friction. The protocol succeeded by being simple enough that anyone can implement it, cheap enough that everyone does, and reliable enough that nobody has to think about it.&lt;/p&gt;
&lt;p&gt;FlowFuse is the industrial data platform designed to bridge this gap between legacy Modbus registers and modern enterprise systems. Our platform provides the connectivity and security layers needed to transform aging infrastructure into a secure, data-driven operation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/</id>
        <title>MQTT vs OPC UA: Why This Question Never Has a Straight Answer</title>
        <summary>Why comparing MQTT and OPC UA is a category error, and how to choose based on requirements rather than marketing</summary>
        <updated>2026-01-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The question itself is broken.&lt;/p&gt;
&lt;p&gt;MQTT moves messages. OPC UA defines meaning. They operate at different layers of the stack. Comparing them is like comparing TCP to JSON.&lt;/p&gt;
&lt;p&gt;Yet the debate persists. Vendors position them as competitors. Consultants bill by the complexity. Your procurement department demands a choice.&lt;/p&gt;
&lt;p&gt;The industry knows better. OPC UA includes MQTT in its spec. Real factories use both: MQTT for telemetry, OPC UA for machine coordination. The technologies have been converging over time.&lt;/p&gt;
&lt;p&gt;The persistent debate exists because the distinction between their purposes remains unclear to many decision-makers.&lt;/p&gt;
&lt;p&gt;This article explains what each does, where they differ, and how to decide based on requirements instead of marketing.&lt;/p&gt;
&lt;h2 id=&quot;what-each-actually-does&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#what-each-actually-does&quot;&gt;What Each Actually Does&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The confusion starts with a category error. Asking &amp;quot;MQTT or OPC UA?&amp;quot; is like asking &amp;quot;HTTP or PostgreSQL?&amp;quot; One moves bytes. The other organizes meaning.&lt;/p&gt;
&lt;h3 id=&quot;mqtt%3A-the-minimalist-messenger&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#mqtt%3A-the-minimalist-messenger&quot;&gt;MQTT: The Minimalist Messenger&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT is a publish-subscribe messaging protocol designed in 1999 for satellite oil pipeline monitoring. It does exactly one thing: &lt;em&gt;move small messages between devices over unreliable networks with minimal overhead.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The entire protocol is remarkably compact:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Publishers send messages to named topics. Subscribers express interest in topic patterns. A broker routes messages from publishers to matching subscribers. That&#39;s it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Device A publishes: &amp;quot;factory/line3/temperature&amp;quot; → 72.4
Device B subscribes: &amp;quot;factory/line3/#&amp;quot;
Broker delivers: Device B receives 72.4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MQTT&#39;s three quality-of-service levels handle network reality:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QoS 0&lt;/strong&gt;: Fire and forget. Message might arrive. Might not. Zero guarantees.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QoS 1&lt;/strong&gt;: At least once delivery. Message arrives one or more times. Duplicates possible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QoS 2&lt;/strong&gt;: Exactly once delivery between client and broker, using a four-way handshake.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The protocol header is 2 bytes. A temperature reading with topic and payload fits in under 50 bytes. This efficiency matters when you&#39;re transmitting over cellular networks, paying per kilobyte, or running on battery-powered sensors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What MQTT doesn&#39;t provide:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MQTT has no concept of data types. That &amp;quot;72.4&amp;quot; could be Celsius, Fahrenheit, or an error code; the protocol doesn&#39;t know or care. It doesn&#39;t validate message structure, enforce schemas, or understand relationships between data points. Topic namespaces are conventions, not specifications. &lt;code&gt;factory/line3/temp&lt;/code&gt; and &lt;code&gt;factory/line3/temperature&lt;/code&gt; and &lt;code&gt;line3/factory/temp&lt;/code&gt; are entirely different topics with no semantic relationship.&lt;/p&gt;
&lt;p&gt;The broker is a single point of failure unless you architect clustering separately. Security implementation depends on broker configuration; MQTT itself focuses on message transport. Discovery mechanisms must be implemented externally; subscribers must know exact topic names in advance or use wildcards and filter received messages.&lt;/p&gt;
&lt;p&gt;MQTT is deliberately minimal. This simplicity at the transport layer enables its flexibility and efficiency.&lt;/p&gt;
&lt;h3 id=&quot;opc-ua%3A-the-semantic-framework&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#opc-ua%3A-the-semantic-framework&quot;&gt;OPC UA: The Semantic Framework&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OPC UA (Unified Architecture) isn&#39;t primarily about moving data; it&#39;s about describing what data means, how it relates to other data, and what operations are valid.&lt;/p&gt;
&lt;p&gt;Released in 2008, OPC UA replaced a fragmented collection of Windows-only industrial protocols with a platform-independent standard. Where MQTT is minimal, OPC UA is comprehensive. The specification spans 37 parts in the core specification covering everything from information modeling to historical data access to alarm conditions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At its core is the address space, a hierarchical graph of nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every piece of industrial equipment is modeled as a connected set of typed nodes. A motor isn&#39;t just a collection of variables; it&#39;s an object with defined properties, methods, and relationships.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Motor (ObjectNode)
├── Speed (VariableNode: Double, Engineering Units: RPM)
├── Temperature (VariableNode: Float, Range: 0-150°C)
├── Status (VariableNode: Enum {Running, Stopped, Fault})
├── Start() (MethodNode: Returns StatusCode)
└── ConnectedTo → Pump_A (Reference: HasComponent)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type system is rich. Variables carry metadata: engineering units, valid ranges, historical access, alarm limits. References define relationships: hierarchical containment, semantic associations, type inheritance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Companion specifications extend this model for specific industries:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Euromap 83 specification defines a complete injection molding machine in OPC UA terms: every sensor, every actuator, every state transition. A client connecting to any Euromap 83 compliant machine encounters the same address space structure. Software written for one machine works with any conforming machine, no custom integration required.&lt;/p&gt;
&lt;p&gt;This semantic interoperability is OPC UA&#39;s primary value. Two systems can exchange meaningful information without prior coordination because the information model is standardized, not just the byte format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OPC UA provides multiple interaction patterns:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data access&lt;/strong&gt;: Read/write variables synchronously&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscriptions&lt;/strong&gt;: Monitor variables, receive change notifications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Methods&lt;/strong&gt;: Execute operations on server objects (start motor, set recipe)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Events&lt;/strong&gt;: Structured alarm and event notifications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Historical access&lt;/strong&gt;: Time-series query interface&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PubSub&lt;/strong&gt; (Part 14): Publish address space updates to message brokers, including MQTT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Security is integrated. Certificate-based authentication, message signing, and encryption are specification requirements, not implementation options. Every OPC UA server must support security policies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The tradeoff is implementation complexity:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Implementing an OPC UA server requires managing an address space, handling multiple services, maintaining subscriptions, and processing security handshakes. Client libraries are measured in megabytes, not kilobytes. A simple &amp;quot;read a value&amp;quot; operation involves session establishment, service negotiation, and potentially certificate exchange.&lt;/p&gt;
&lt;p&gt;This overhead is impractical for battery-powered sensors with infrequent reporting requirements. It&#39;s appropriate for a $2M manufacturing cell where understanding that a temperature reading represents &amp;quot;bearing temperature on the output shaft of motor 3, measured in Celsius, with a normal operating range of 40-65°C and critical alarm at 85°C&amp;quot; matters.&lt;/p&gt;
&lt;h3 id=&quot;the-layer-mismatch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#the-layer-mismatch&quot;&gt;The Layer Mismatch&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Think about the OSI model, that seven-layer networking abstraction everyone learns and immediately forgets:&lt;/p&gt;
&lt;p&gt;MQTT operates at the application layer of the OSI model. It is a messaging protocol that happens to carry application data, but what that data represents is outside its scope.&lt;/p&gt;
&lt;p&gt;OPC UA also operates at the application layer. It defines data models, type systems, and semantic relationships. Transport is abstracted; OPC UA can run over TCP, HTTPS, WebSockets, or MQTT.&lt;/p&gt;
&lt;p&gt;Comparing them is comparing different architectural concerns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MQTT answers: &amp;quot;How do I efficiently move this message from publisher to subscriber?&amp;quot;&lt;/li&gt;
&lt;li&gt;OPC UA answers: &amp;quot;What does this data represent, and how does it relate to other data?&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They&#39;re not competing solutions to the same problem. They&#39;re solving different problems that happen to intersect in industrial automation architectures.&lt;/p&gt;
&lt;h3 id=&quot;the-convergence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#the-convergence&quot;&gt;The Convergence&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OPC UA &lt;a href=&quot;https://reference.opcfoundation.org/Core/Part14/v104/docs/&quot;&gt;Part 14&lt;/a&gt; specifies OPC UA PubSub, a publish-subscribe model that can use MQTT as its transport mechanism. An OPC UA server publishes address space updates as MQTT messages encoded with OPC UA&#39;s type information.&lt;/p&gt;
&lt;p&gt;MQTT Sparkplug B introduced structured payloads inspired by OPC UA’s semantic modeling concepts, adding type definitions and metric metadata to MQTT payloads. A Sparkplug message doesn&#39;t just carry &amp;quot;72.4&amp;quot;; it carries &amp;quot;Temperature (Float32, Engineering Units: °C, timestamp: 1704470400000) = 72.4&amp;quot;.&lt;/p&gt;
&lt;p&gt;The technologies are converging, not diverging. Industry 4.0 architectures increasingly use both: OPC UA for machine-to-machine communication where semantic interoperability matters, MQTT for high-frequency telemetry where bandwidth efficiency matters, and OPC UA PubSub over MQTT where both matter.&lt;/p&gt;
&lt;p&gt;Yet vendor marketing, procurement processes, and consultant billable hours perpetuate the false choice. The question isn&#39;t &amp;quot;which one?&amp;quot;; it&#39;s &amp;quot;which one for what?&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;where-they-actually-differ&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#where-they-actually-differ&quot;&gt;Where They Actually Differ&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding real differences requires moving past marketing claims to examine what each technology optimizes for and what constraints it accepts as tradeoffs.&lt;/p&gt;
&lt;h3 id=&quot;network-assumptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#network-assumptions&quot;&gt;Network Assumptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT was designed for unreliable networks. The protocol was built for satellite links where latency is measured in seconds and packet loss is expected. QoS levels give explicit control over delivery guarantees versus bandwidth cost. The persistent session feature lets devices reconnect after network interruptions and resume exactly where they left off, receiving any messages published while offline.&lt;/p&gt;
&lt;p&gt;OPC UA was designed for reliable networks and builds on that foundation. The request-response model expects millisecond response times. Session management assumes stable connections. Historical access and complex queries make sense when networks can support them. Running OPC UA over cellular or satellite links works, This operates outside the protocol’s primary design parameters.&lt;/p&gt;
&lt;p&gt;This difference cascades into deployment patterns. MQTT excels when you&#39;re collecting data from thousands of remote assets: wind turbines, pipeline sensors, fleet vehicles. OPC UA excels when you&#39;re integrating systems within a plant where network quality is controlled and semantic understanding matters more than last-mile efficiency.&lt;/p&gt;
&lt;h3 id=&quot;discovery-and-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#discovery-and-configuration&quot;&gt;Discovery and Configuration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Walk up to an OPC UA server with a generic client. Hit the discovery endpoint. The server returns its complete address space: every node, every relationship, every available operation. You can browse the hierarchy, inspect type definitions, and understand capabilities without reading documentation. The server is self-describing.&lt;/p&gt;
&lt;p&gt;MQTT itself does not define a discovery mechanism; discovery is typically handled through external conventions or platform-specific tooling. Topic structures and available data must be known in advance or determined through external documentation. The broker doesn&#39;t know what topics exist until something publishes to them. Subscribers must know exact topic patterns in advance or use wildcards and filter everything they receive. Topic naming is pure convention with no enforcement.&lt;/p&gt;
&lt;p&gt;This reflects philosophical differences. OPC UA optimizes for systems integration where understanding what&#39;s available matters. MQTT optimizes for data distribution where publishers and subscribers coordinate through external mechanisms: configuration files, documentation, human agreement.&lt;/p&gt;
&lt;p&gt;In practice, MQTT deployments build discovery and schema management in separate layers. Sparkplug defines topic namespaces and birth certificates that announce available metrics. Cloud platforms provide device registries and schema repositories. These additions extend MQTT&#39;s core capabilities to address requirements in complex industrial systems.&lt;/p&gt;
&lt;h3 id=&quot;state-and-synchronization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#state-and-synchronization&quot;&gt;State and Synchronization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OPC UA maintains state. The server knows current variable values. Clients can read the current state at any time. Subscriptions detect changes and notify clients. If a client disconnects and reconnects, it can query what changed during the outage. The historical access service provides time-series queries.&lt;/p&gt;
&lt;p&gt;MQTT focuses on message transport rather than state management. The broker routes messages but doesn&#39;t track values. If you want the current temperature, someone has to publish it after you subscribe. The &amp;quot;retained message&amp;quot; feature lets the broker store the last message per topic, but that&#39;s a single value with no history or change tracking. There&#39;s no way to query &amp;quot;what happened between 2PM and 3PM yesterday?&amp;quot;&lt;/p&gt;
&lt;p&gt;This difference shapes architecture. OPC UA servers are often treated as authoritative sources of truth within an architecture. MQTT systems require separate databases if historical data or current state matters. Time-series databases like InfluxDB or Timescale became standard MQTT architecture components specifically because MQTT itself doesn&#39;t retain data.&lt;/p&gt;
&lt;h3 id=&quot;security-models&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#security-models&quot;&gt;Security Models&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OPC UA integrates security into the specification. Every implementation must support certificate-based authentication and encrypted sessions. Security policies are negotiated during connection establishment. Message signing and encryption are first-class protocol features. The specification defines exactly how certificates should be managed, what cipher suites are allowed, and how security auditing works.&lt;/p&gt;
&lt;p&gt;MQTT delegates security implementation to the broker and transport layer rather than defining it within the protocol specification. MQTT 3.1.1 supports username/password authentication and expects TLS encryption to happen at the transport layer, but these are optional features. Securing an MQTT deployment means configuring the broker correctly, managing TLS certificates, implementing access control lists, and possibly adding an authentication service. Two MQTT brokers can have completely different security characteristics.&lt;/p&gt;
&lt;p&gt;MQTT 5.0 added enhanced authentication mechanisms, but security remains a broker implementation concern rather than a protocol guarantee. In practice, MQTT security depends on broker configuration and deployment choices, ranging from open development environments to enterprise-grade implementations with full authentication and encryption.&lt;/p&gt;
&lt;p&gt;For regulated industries (pharmaceuticals, food processing, utilities) OPC UA&#39;s integrated security approach often simplifies compliance documentation, as the protocol specification itself defines security requirements rather than depending on correct broker configuration.&lt;/p&gt;
&lt;h3 id=&quot;bandwidth-and-overhead&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#bandwidth-and-overhead&quot;&gt;Bandwidth and Overhead&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT&#39;s 2-byte header and compact binary format minimize overhead. Publishing a temperature reading consumes roughly 50 bytes including topic and payload. Over a cellular connection transmitting 10,000 readings per day, that&#39;s under 500KB. At $1 per megabyte (typical M2M cellular rates), you&#39;re paying $0.50 per device per day just for bandwidth.&lt;/p&gt;
&lt;p&gt;OPC UA&#39;s overhead varies by transport, but even optimized binary encoding uses hundreds of bytes per value due to security handshakes, message signatures, and type information. The same 10,000 readings might consume 5-10MB. At cellular data rates, that&#39;s $5-10 per device per day.&lt;/p&gt;
&lt;p&gt;For battery-powered remote sensors, this difference determines project feasibility. For plant-floor equipment connected via ethernet, it&#39;s less significant. The question isn&#39;t which protocol has less overhead; it&#39;s whether that overhead matters in your deployment.&lt;/p&gt;
&lt;h3 id=&quot;scalability-patterns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#scalability-patterns&quot;&gt;Scalability Patterns&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT scales horizontally through broker clustering. Mosquitto, EMQX, and HiveMQ all support distributed deployments where multiple broker instances share message routing. Add brokers as subscriber count grows. Millions of devices can publish to a broker cluster, and the brokers handle distribution to subscribers.&lt;/p&gt;
&lt;p&gt;OPC UA scales through federation and aggregation. An aggregation server connects to multiple OPC UA devices, presents a unified address space, and handles client connections. Clients connect to the aggregator instead of individual devices. Adding devices means configuring the aggregator, not changing the client.&lt;/p&gt;
&lt;p&gt;These patterns fit different problems. MQTT&#39;s approach works when you&#39;re collecting data from massive device fleets. OPC UA&#39;s approach works when you&#39;re building a plant information system that integrates hundreds of machines.&lt;/p&gt;
&lt;h2 id=&quot;the-unified-namespace-question&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#the-unified-namespace-question&quot;&gt;The Unified Namespace Question&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Just use Unified Namespace&amp;quot; appears in every MQTT versus OPC UA discussion, framed as the answer that makes protocol choice irrelevant.&lt;/p&gt;
&lt;p&gt;It is not sufficient.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;UNS&lt;/a&gt; is an integration pattern: all plant data flows through a central MQTT broker with hierarchical topics. Systems publish once. Systems subscribe to what they need. Instead of 200 point-to-point connections, you have one hub. Add systems without breaking existing integrations. This solves real problems in brownfield plants.&lt;/p&gt;
&lt;p&gt;But UNS doesn&#39;t eliminate protocol choice. It relocates it.&lt;/p&gt;
&lt;p&gt;Your OPC UA machines still speak OPC UA. Edge gateways consume that semantic data, translate it to MQTT Sparkplug, and publish to the UNS broker. Protocol choice happens at the edge. Your MES connects via OPC UA when it needs semantic precision, subscribes via MQTT when it just needs telemetry. Same downstream system, different protocols for different needs.&lt;/p&gt;
&lt;p&gt;UNS centralizes data flow. It doesn&#39;t centralize protocol decisions; those still happen at every connection point based on the same factors: semantic requirements, bandwidth constraints, scale characteristics, native support.&lt;/p&gt;
&lt;p&gt;The question changes from &amp;quot;MQTT or OPC UA for everything?&amp;quot; to &amp;quot;MQTT or OPC UA for this specific connection?&amp;quot;&lt;/p&gt;
&lt;p&gt;UNS is valuable architecture. It&#39;s not a protocol substitute.&lt;/p&gt;
&lt;h3 id=&quot;how-to-actually-decide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#how-to-actually-decide&quot;&gt;How to Actually Decide&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most protocol comparisons start with feature matrices. Yours should start with data flow diagrams.&lt;/p&gt;
&lt;p&gt;Map your requirements first, not your preferences. Draw every connection in your architecture. Each arrow represents a data flow with distinct characteristics that should guide protocol selection. A temperature sensor transmitting hourly readings over satellite has fundamentally different needs than a CNC machine coordinating with your MES where both systems must agree on what &amp;quot;cycle complete&amp;quot; means.&lt;/p&gt;
&lt;p&gt;Consider four factors for each data flow:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Semantic requirements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Do the connected systems need shared understanding of what data means? If your MES and machines must coordinate on production states, downtime codes, and quality parameters, OPC UA&#39;s information modeling provides that common language. If you&#39;re collecting sensor data for ML analysis where patterns matter more than metadata, MQTT with basic context suffices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Network constraints&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let the infrastructure decide. Gigabit plant ethernet makes protocol overhead less critical; choose based on semantic needs. Cellular links where you pay per megabyte make the difference between MQTT&#39;s 50-byte messages and OPC UA&#39;s kilobyte handshakes a line-item cost. Satellite connections with multi-second latency benefit from MQTT&#39;s QoS handling regardless of other factors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Native protocol support&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Work with your equipment, not against it. Siemens PLCs, Rockwell controllers, and Schneider drives speak OPC UA natively. AWS IoT expects MQTT. HiveMQ clusters scale MQTT efficiently. Leveraging native support reduces integration complexity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Scale characteristics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Five hundred vibration sensors streaming to cloud storage align with MQTT&#39;s horizontal scaling through broker clusters. Fifty machines requiring discovered operations and validated method calls align with OPC UA&#39;s self-describing address spaces. Different problems, different optimal solutions.&lt;/p&gt;
&lt;p&gt;For example, you&#39;re connecting 50 CNC machines, 500 environmental sensors, &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;MES&lt;/a&gt;, predictive maintenance, and cloud analytics.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- Machines → Edge: OPC UA (semantic interoperability for production coordination)
- Sensors → Edge: MQTT (efficient collection at scale)
- Edge → Cloud: MQTT Sparkplug (metadata preservation with bandwidth efficiency)  
- Edge → MES: OPC UA (shared understanding of manufacturing operations)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four data flows, two protocols, zero false choices. The architecture reflects requirements, not vendor marketing.&lt;/p&gt;
&lt;p&gt;The pattern emerges naturally: OPC UA where systems must share meaning. MQTT where efficiency and scale matter. OPC UA PubSub when you need both. Protocol choice becomes a local optimization within each data flow, not a global architecture decision that locks you into one approach.&lt;/p&gt;
&lt;h2 id=&quot;moving-forward&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/opcua-vs-mqtt/#moving-forward&quot;&gt;Moving Forward&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The persistence of this debate reveals something: we&#39;re still thinking protocol-first instead of problem-first.&lt;/p&gt;
&lt;p&gt;Stop asking &amp;quot;which protocol?&amp;quot; Start mapping your actual data flows and constraints. That pipeline sensor? &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt;. That machine coordination? &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;OPC UA&lt;/a&gt;. That edge-to-cloud telemetry? &lt;a href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/&quot;&gt;Sparkplug&lt;/a&gt;. The modern industrial stack uses multiple protocols because different problems have different optimal solutions.&lt;/p&gt;
&lt;p&gt;The convergence technologies (OPC UA PubSub, MQTT Sparkplug, edge gateways) prove the industry already knows this. Protocol choice is becoming a local optimization, not a global architecture decision.&lt;/p&gt;
&lt;p&gt;Your next project: map requirements first, select protocols second. Use semantic modeling where systems must share meaning. Use efficient messaging where scale and bandwidth matter. Use both when both matter.&lt;/p&gt;
&lt;p&gt;The right question isn&#39;t &amp;quot;MQTT or OPC UA?&amp;quot;&lt;/p&gt;
&lt;p&gt;It&#39;s &amp;quot;MQTT where? OPC UA where? Both where?&amp;quot;&lt;/p&gt;
&lt;p&gt;Answer that based on your requirements, not vendor marketing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/</id>
        <title>Beyond Kepware: Why Modern Industrial Connectivity Demands a Second Look</title>
        <summary>Why per-tag pricing, scale penalties, and private-equity ownership change the risk equation</summary>
        <updated>2026-01-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Kepware isn&#39;t chosen, it&#39;s assumed. It appears in budgets like line items for electricity or insurance. No one questions it. No one compares it. It just... goes in.&lt;/p&gt;
&lt;p&gt;And that&#39;s exactly the problem. You&#39;ve been paying luxury car prices, often well into six figures, for a data shuttle bus. Reliable? Sure. But while Kepware moves your data, it also moves your money straight into per-tag, per-connection licensing fees that explode as you scale. Worse, you don&#39;t control your own data. And now, with TPG&#39;s $600 million acquisition closing in early 2026, you&#39;re betting on a company mid-transition, mid-uncertainty, mid-everything.&lt;/p&gt;
&lt;p&gt;The question isn&#39;t whether Kepware works. It&#39;s whether you can afford to keep not asking better questions.&lt;/p&gt;
&lt;h2 id=&quot;why-you-picked-kepware-(and-why-that-made-sense)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/#why-you-picked-kepware-(and-why-that-made-sense)&quot;&gt;Why You Picked Kepware (And Why That Made Sense)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we talk about why Kepware shouldn&#39;t be your next choice, let&#39;s acknowledge why it was your last one. Because the logic that got you here wasn&#39;t wrong, it was just incomplete.&lt;/p&gt;
&lt;p&gt;You didn&#39;t choose Kepware. Kepware chose you.&lt;/p&gt;
&lt;p&gt;Your integrator spec&#39;d it. The equipment vendor had already validated it. Your boss signed off without discussion because &amp;quot;everyone uses Kepware.&amp;quot; When you&#39;re staring down a plant expansion deadline with production breathing down your neck, safe beats optimal every time.&lt;/p&gt;
&lt;p&gt;And Kepware was safe. Until the bills started compounding.&lt;/p&gt;
&lt;p&gt;$15,000 for the initial license seemed reasonable. Then came additional tags for the new production line. New drivers for equipment you hadn&#39;t planned for. A redundant server because IT flagged single points of failure. Eighteen months later, you&#39;re at 20x annually, and nobody remembers approving half of it.&lt;/p&gt;
&lt;p&gt;Here&#39;s what actually happened: Kepware didn&#39;t win on technical merit. It won on timing and driver ubiquity.&lt;/p&gt;
&lt;p&gt;In the early 2000s, industrial connectivity was genuinely hard. Proprietary PLC protocols. Sparse documentation. Vendors actively hostile to third-party integration. Kepware invested aggressively in driver development, by 2010, if a PLC existed in North America, Kepware almost certainly supported it. That created a network effect system integrators couldn&#39;t ignore. Standardization followed. Equipment vendors tested against it. PTC&#39;s $100 million acquisition in 2016 cemented the strategy.&lt;/p&gt;
&lt;p&gt;You didn&#39;t get tricked. Lock-in happened through entirely normal operations.&lt;/p&gt;
&lt;p&gt;But here&#39;s what the sales process never highlights: escalating switching costs aren&#39;t a side effect. They&#39;re the business model.&lt;/p&gt;
&lt;p&gt;Your goal was never &amp;quot;buy Kepware.&amp;quot; Your goal was to move OT data where it matters, fast, reliably, without unnecessary drama.&lt;/p&gt;
&lt;h2 id=&quot;kepware-pricing-explained%3A-how-costs-escalate-as-you-scale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/#kepware-pricing-explained%3A-how-costs-escalate-as-you-scale&quot;&gt;Kepware Pricing Explained: How Costs Escalate as You Scale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ROI spreadsheet your vendor showed you was accurate. It just ended when the story was just beginning.&lt;/p&gt;
&lt;p&gt;You approved Kepware because the first-year quote made sense: base license, sufficient tags for operations, drivers for your PLCs. Number aligned with budget. Decision closed.&lt;/p&gt;
&lt;p&gt;Then your plant didn&#39;t stop.&lt;/p&gt;
&lt;p&gt;New production line? More tags needed. Different PLC brand? New driver license. Maintenance kicks in at 18-20%, calculated not on your starting point, but on everything you&#39;ve added since. IT finally gets redundancy approved. Operations wants visualization. Kepware doesn&#39;t do that, so you&#39;re buying elsewhere. New vendor. New purchase order.&lt;/p&gt;
&lt;p&gt;Year two: more equipment, more expansion. Your historian works with Kepware. Your analytics tool doesn&#39;t. Middleware required. Management wants remote access. Cloud gateway added. Every item individually justified. Every purchase properly approved. All operationally necessary.&lt;/p&gt;
&lt;p&gt;Year three: you&#39;re maintaining the entire accumulated infrastructure. Tag costs scaled with production capacity. Integration expenses compounded with each system added.&lt;/p&gt;
&lt;p&gt;What wasn&#39;t emphasized during procurement: Kepware moves data. Full stop. You still need separate systems for storage (historian), translation (middleware), visualization (dashboards), and processing (analytics). The purchase order said &amp;quot;connectivity.&amp;quot; The actual infrastructure required five different vendors.&lt;/p&gt;
&lt;p&gt;The pricing model punishes scale. More capacity needs more tags. More tags mean higher licensing. Higher licensing means steeper maintenance. Your costs climb while the underlying technology expenses, bandwidth, compute, storage, have been dropping for years.&lt;/p&gt;
&lt;p&gt;Per-tag pricing doesn&#39;t match infrastructure reality. It matches what the market has tolerated. The actual cost of transmitting ten thousand data points versus one thousand? Essentially identical. Cloud providers know this. Modern software companies abandoned this model. The technology doesn&#39;t require metered billing, it just permits it.&lt;/p&gt;
&lt;p&gt;Kepware charges per-tag because nobody&#39;s forced them to change.&lt;/p&gt;
&lt;p&gt;You thought you bought connectivity. What you actually got was a billing structure that monetizes your success. Every expansion. Every new line. Every added system. Kepware extracts revenue from it. This isn&#39;t a partnership, it&#39;s value extraction wearing an enterprise license agreement.&lt;/p&gt;
&lt;h2 id=&quot;why-kepware-makes-less-sense-in-2026&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/#why-kepware-makes-less-sense-in-2026&quot;&gt;Why Kepware Makes Less Sense in 2026&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Five years ago, questioning Kepware meant gambling with production reliability. The alternatives weren&#39;t proven.&lt;/p&gt;
&lt;p&gt;Today they are. And fundamental shifts made the old calculation obsolete.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protocol secrecy collapsed.&lt;/strong&gt; Kepware&#39;s advantage rested entirely on PLC manufacturers hiding their communication protocols. Documentation was unavailable. Reverse engineering was mandatory. Now every significant protocol specification is publicly published. Manufacturers provide detailed technical guides. Industry bodies standardized everything. What once demanded rare expertise is now freely available knowledge. The technical moat largely dried up. The pricing hasn&#39;t acknowledged it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure economics flipped.&lt;/strong&gt; Handling 50,000 tags used to mean purchasing dedicated servers, implementing redundant hardware, staffing IT personnel. Real capital expenditure. Today that same capacity runs on $200 monthly cloud compute. The underlying cost dropped 90%. Kepware&#39;s licensing model operates as though nothing changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Complexity barriers vanished.&lt;/strong&gt; Configuring Kepware required certified specialists. Three-day deployments minimum. Formal training requirements. Troubleshooting demanded protocol knowledge most engineers lacked. Modern platforms offer drag-and-drop setup, automatic device discovery, visual configuration. What took specialists three days, operations teams complete in two hours. The complexity that forced expensive integrator relationships disappeared.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fragmented purchases became unified platforms.&lt;/strong&gt; Kepware moved data. Full stop. You still needed separate historians, visualization tools, cloud gateways, middleware, analytics platforms. Five vendors. Five contracts. Five integration projects. Modern platforms ship unified, not assembled from parts, designed as integrated systems. The integration tax evaporated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And private equity bought Kepware for $600 million.&lt;/strong&gt; TPG&#39;s deal closes early 2026. Private equity doesn&#39;t maintain operations, it maximizes returns. That often means price increases, forced product bundles, or operational restructuring designed to extract more from existing customers. It&#39;s the same playbook every time.&lt;/p&gt;
&lt;p&gt;You&#39;re not evaluating Kepware as it is. You&#39;re evaluating what it becomes under new ownership carrying $600 million in return expectations.&lt;/p&gt;
&lt;p&gt;The window&#39;s narrow. Before new pricing hits. Before renewals reflect new ownership. While you control the timing instead of reacting to changes forced on you.&lt;/p&gt;
&lt;p&gt;The safe choice five years ago became the risky bet today. Alternatives matured. Economics shifted fundamentally. Ownership transferred.&lt;/p&gt;
&lt;p&gt;Evaluate now, or negotiate from weakness later.&lt;/p&gt;
&lt;h2 id=&quot;the-bottom-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/kepware-opcua-better-alternative/#the-bottom-line&quot;&gt;The Bottom Line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You didn&#39;t select Kepware after rigorous evaluation. You selected it because it was the path of least resistance.&lt;/p&gt;
&lt;p&gt;Least resistance meant proven reliability. Integrator familiarity. Budget pre-approval. Zero pushback.&lt;/p&gt;
&lt;p&gt;But resistance-free had costs. Not just licensing, per-tag economics that scale against you. Integration overhead that multiplies vendor relationships. Lock-in that monetizes every operational expansion.&lt;/p&gt;
&lt;p&gt;And now adds new risk: private equity ownership with $600 million in performance expectations.&lt;/p&gt;
&lt;p&gt;The fundamentals shifted. Protocols became open. Infrastructure costs dropped 90%. Modern platforms integrated what previously required assembly. The technical and economic moats that justified Kepware as default evaporated.&lt;/p&gt;
&lt;p&gt;You&#39;re not constrained by technology. You&#39;re constrained by inertia.&lt;/p&gt;
&lt;p&gt;Kepware functions reliably. That&#39;s not disputed. But reliability alone doesn&#39;t justify paying 2015 prices for 2026 infrastructure when alternatives provide more capability at lower total cost.&lt;/p&gt;
&lt;p&gt;Evaluate alternatives now from strength. Or negotiate renewals later from weakness under new ownership terms.&lt;/p&gt;
&lt;p&gt;Kepware won through early dominance and ecosystem lock-in. That&#39;s separate from being the right architecture for current operations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/</id>
        <title>FlowFuse 2.26: Bringing access-controls to your MCP nodes</title>
        <summary>FlowFuse 2.26: Bringing access-controls to your MCP nodes</summary>
        <updated>2026-01-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;With the holiday break sitting in the middle of this release cycle, it&#39;s a smaller release than usual this month. But that hasn&#39;t stopped us continuing to make the FlowFuse Expert even more useful.&lt;/p&gt;
&lt;h2 id=&quot;role-based-access-control-for-your-mcp-tools&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#role-based-access-control-for-your-mcp-tools&quot;&gt;Role-based access control for your MCP tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Following on the the introduction of &lt;a href=&quot;https://flowfuse.com/changelog/2025/12/ff-expert-mcp-insights/&quot;&gt;FlowFuse Expert MCP-Powered Insights&lt;/a&gt; we have added annotations to the FlowFuse MCP nodes and linked them up with the FlowFuse roles.
This permits a level of control over who can access what. This is just a first step, we will be working in the area over the next few iterations.&lt;/p&gt;
&lt;p&gt;The MCP nodes now allow you to set some standard annotations to give the platform a hint as to what type of action the node performs. This lets you separate tools that provide read-only information from those that make potentially-destructive changes.&lt;/p&gt;
&lt;p&gt;Within the FlowFuse team, you can then use the granular RBAC feature to configure what users have access to the different types of node.&lt;/p&gt;
&lt;p&gt;For example, Viewer role users can have access to read-only nodes, whilst Owners get to access the full range of tools. These roles can be customised for each Application within the team.&lt;/p&gt;
&lt;p&gt;The annotations we apply are part of the MCP standard, so will be recognised by your own Agents and LLMs.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MCP Server Tool Node with new annotations&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-annotations.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;MCP Server Tool Node with new annotations&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;integrating-flowfuse-expert-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#integrating-flowfuse-expert-with-node-red&quot;&gt;Integrating FlowFuse Expert with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This release also brings some new abilities for the FlowFuse Expert to help you do things inside Node-RED itself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Streamlined Node Installation:&lt;/strong&gt; When the Expert suggests a node module, it can now automatically open the Palette Manager and filter for the correct package, leaving you just one click away from installation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct Flow Imports:&lt;/strong&gt; When the Expert provides demo flows, you no longer need to copy-paste JSON. The Expert can now inject those flows directly into your editor, ready for deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure you&#39;ve updated the &lt;code&gt;@flowfuse/nr-assistant&lt;/code&gt; module inside your instance to unlock these new capabilities.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert Install Node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-expert-install-node.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert integration with the Palette Manager&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.26 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.26.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Reach out on GitHub or social media!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/flowfuse-release-2-26/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/what-is-system-integrator/</id>
        <title>What Is a System Integrator? Understanding Manufacturing&#39;s Most Misunderstood Role</title>
        <summary>The specialists who make your factory equipment talk to your business software</summary>
        <updated>2026-01-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/what-is-system-integrator/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Most factories don&#39;t get built all at once. They evolve. Someone buys a robot in 2018. A conveyor system gets added when production ramps up. Last year, a vision system showed up because quality was slipping. Every piece from a different vendor, every piece with its own manual, its own software, its own way of doing things.&lt;/p&gt;
&lt;p&gt;And somehow, it all has to work together.&lt;/p&gt;
&lt;p&gt;That&#39;s what system integrators do. They look at what you&#39;ve got and figure out how to make it run as one system. They write the code that connects it, wire the panels that power it, and test it until it works the way it needs to. When they&#39;re done right, everything just runs: the line moves, parts flow, production hits its numbers.&lt;/p&gt;
&lt;p&gt;But here&#39;s what most people don&#39;t see: the complexity behind making that happen. Even if you work with system integrators regularly, the full scope of what they do often stays hidden beneath the surface. This article pulls back that curtain.&lt;/p&gt;
&lt;h2 id=&quot;what-system-integrators-actually-do%2C-and-why-they-matter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#what-system-integrators-actually-do%2C-and-why-they-matter&quot;&gt;What System Integrators Actually Do, and Why They Matter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A system integrator is a partner that takes separate pieces of technology (from factory floor equipment to business software) and makes them work as one system.&lt;/p&gt;
&lt;p&gt;But that definition doesn&#39;t capture the scope. The work spans two worlds that don&#39;t naturally speak to each other.&lt;/p&gt;
&lt;p&gt;On one side, you have operational technology (OT): the physical equipment that runs your factory. Robots, PLCs, conveyors, sensors, vision systems, SCADA systems. On the other side, you have information technology (IT): the software that runs your business. ERP systems, MES platforms, databases, analytics tools.&lt;/p&gt;
&lt;p&gt;System integrators connect both. And that&#39;s where things get complicated.&lt;/p&gt;
&lt;h3 id=&quot;discovery-and-diagnosis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#discovery-and-diagnosis&quot;&gt;Discovery and Diagnosis&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The work begins with understanding the actual problem. A line keeps jamming because two machines won&#39;t sync. Production data sits trapped in SCADA and can&#39;t reach your ERP for scheduling decisions. Quality defects have no connection to process parameters. These aren&#39;t isolated issues: they&#39;re integration failures.&lt;/p&gt;
&lt;p&gt;A system integrator walks your plant with a specific lens. They document what equipment you&#39;re running, which protocols each device speaks, where IT and OT systems touch or fail to. They identify the gaps: a PLC speaking Modbus trying to feed a cloud platform, an MES that can&#39;t pull real-time SCADA status, a quality database disconnected from traceability. They map not just what&#39;s broken, but why, and what fixing it actually requires.&lt;/p&gt;
&lt;h3 id=&quot;architecture-and-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#architecture-and-design&quot;&gt;Architecture and Design&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Then comes architecture. They design how everything communicates: OPC-UA for machine data, MQTT for sensor networks, APIs for enterprise integration. They map data flow with an understanding of latency, volume, and the cybersecurity boundaries between factory and business networks. They specify edge computing where real-time decisions matter and cloud connectivity where analytics adds value. The result accounts for your existing infrastructure, your future needs, and the reality that factories can&#39;t afford downtime.&lt;/p&gt;
&lt;h3 id=&quot;implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#implementation&quot;&gt;Implementation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The build phase makes it real. Controls engineers program PLCs and configure SCADA. Electricians assemble panels and run cable. Network engineers deploy industrial Ethernet with the redundancy and determinism that production demands. Software developers write the middleware that translates between incompatible systems and build dashboards that turn raw data into decisions.&lt;/p&gt;
&lt;h3 id=&quot;testing-and-commissioning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#testing-and-commissioning&quot;&gt;Testing and Commissioning&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Commissioning proves it works. They test components in controlled environments, verify equipment in your actual plant conditions, and stress the complete system under load. They simulate equipment failures, run at maximum throughput, validate data accuracy from sensor to business report. They tune controller performance and set alarm thresholds. Nothing goes live until it runs reliably across all shifts and your team knows how to operate it.&lt;/p&gt;
&lt;h3 id=&quot;why-this-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#why-this-matters&quot;&gt;Why This Matters&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modern manufacturing doesn&#39;t work without integration. You can&#39;t optimize production without data. You can&#39;t get data without connectivity. You can&#39;t connect systems that speak different languages and live in different networks. System integrators are the bridge builders who make your factory floor talk to your business systems. They turn equipment investments into operational capability. They make the difference between a factory that runs and one that competes.&lt;/p&gt;
&lt;p&gt;But even for those familiar with the role, the true complexity often gets underestimated.&lt;/p&gt;
&lt;h2 id=&quot;why-system-integration-is-more-complex-than-it-appears&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#why-system-integration-is-more-complex-than-it-appears&quot;&gt;Why System Integration Is More Complex Than It Appears&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most people who work with system integrators understand what they do at a high level. But the depth and breadth of the work often gets compressed into simple categories that don&#39;t capture reality.&lt;/p&gt;
&lt;p&gt;&amp;quot;They install robots.&amp;quot; That&#39;s maybe 10% of the work (and often not the hardest part). &amp;quot;They&#39;re industrial electricians.&amp;quot; Electricians are crucial team members, but they&#39;re one specialty among many. &amp;quot;They handle automation projects.&amp;quot; True, but that doesn&#39;t explain the challenge of making a 2015 Siemens PLC talk to a 2023 cloud analytics platform while maintaining cybersecurity boundaries and microsecond-level timing precision.&lt;/p&gt;
&lt;p&gt;The real complexity comes from operating across multiple domains simultaneously. A single project might require technical breadth across both factory floor protocols (Modbus, Profinet, EtherNet/IP) and enterprise systems (REST APIs, SQL databases, message queues). Understanding when to use edge computing versus cloud processing. Balancing real-time control requirements with data analytics needs.&lt;/p&gt;
&lt;p&gt;Different industries have different requirements. Food processing needs washdown-rated equipment and FDA compliance. Automotive requires high-speed deterministic networks and traceability. Pharmaceuticals demand validation documentation and 21 CFR Part 11 compliance. An integrator can&#39;t just transplant solutions between industries: domain expertise matters.&lt;/p&gt;
&lt;p&gt;Modern factories still run equipment from the 1990s alongside brand-new IoT sensors. Integration means making 30-year-old systems participate in Industry 4.0 initiatives without replacing everything (because replacing everything isn&#39;t an option). Legacy systems present unique challenges that require both historical knowledge and modern techniques.&lt;/p&gt;
&lt;p&gt;Integration projects touch production, IT, quality, maintenance, and management. Each group has different priorities, different vocabularies, and different success metrics. The integrator must translate between them and build systems that serve all stakeholders. This organizational complexity often proves harder than the technical challenges.&lt;/p&gt;
&lt;p&gt;Factories can&#39;t stop for testing. Integration work happens around production schedules, often during limited downtime windows. A mistake can halt a production line costing thousands per minute. Every decision carries operational risk that must be carefully managed. The pressure to get it right the first time is immense.&lt;/p&gt;
&lt;p&gt;This complexity (the need to work across multiple domains, technologies, and organizational boundaries) is also why the tools integrators use have had to evolve. The traditional approach that worked for decades simply can&#39;t keep up anymore.&lt;/p&gt;
&lt;h2 id=&quot;how-modern-tools-are-changing-system-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#how-modern-tools-are-changing-system-integration&quot;&gt;How Modern Tools Are Changing System Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;System integration used to mean custom work every time. Integrators hard-coded point-to-point connections between machines and systems. Change a sensor, and you risk breaking the ERP connection. Scale that across a factory, and you end up with &amp;quot;spaghetti architecture,&amp;quot; where everything depends on everything else.&lt;/p&gt;
&lt;p&gt;That approach no longer works. Industry 4.0 has changed manufacturing priorities. Data isn&#39;t just a byproduct of production: it&#39;s the foundation for optimization, predictive maintenance, and competitive advantage. Modern factories generate massive amounts of data, evolve quickly, and can&#39;t afford brittle, one-off integrations.&lt;/p&gt;
&lt;p&gt;The industry is moving toward architectures like the &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt;. Instead of systems talking directly to each other, data flows to a central hub. A PLC publishes data once. MES, ERP, analytics platforms all subscribe to it. Add a new system, and it just subscribes. No rewiring. No breaking existing connections.&lt;/p&gt;
&lt;p&gt;This shift demands different tools. Tools that support many protocols without custom drivers. Tools that are quick to understand and easy to maintain. Tools where you can see how data flows at a glance instead of digging through legacy code.&lt;/p&gt;
&lt;p&gt;Several approaches address these challenges. One that many integrators are adopting combines flow-based programming with enterprise management capabilities. &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; provides the foundation for visual integration. Integrators build flows by connecting nodes instead of writing everything from scratch. Integrations that once took days can often be configured in hours. Node-RED already supports the protocols integrators rely on daily (MQTT, OPC-UA, Modbus, HTTP, and more) without custom development.&lt;/p&gt;
&lt;p&gt;But Node-RED on its own presents challenges at scale. A single factory might run dozens of Node-RED instances across multiple production lines. Multiply that across multiple sites, and suddenly you&#39;re managing hundreds or thousands of separate installations. Version control becomes critical: you need to know which flows are running where. Updates need careful orchestration: you can&#39;t afford to push changes that break production systems. Teams need visibility into what&#39;s deployed and the ability to roll back when necessary.&lt;/p&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; extends Node-RED&#39;s capabilities for production environments. It adds the enterprise management layer that large-scale deployments require: centralized control across all your Node-RED instances, version tracking for every flow change, and the ability to test updates in staging environments before they touch live equipment. What was once a prototyping tool becomes a platform you can trust in production.&lt;/p&gt;
&lt;p&gt;The combination enables new patterns. Node-RED can run at the edge, close to machines, processing data locally and sending only what matters upstream. FlowFuse manages those edge deployments from a central location, giving you visibility and control without constant site visits. Teams can develop changes in one environment, test them against digital twins, then deploy systematically across production sites, reducing risk and eliminating the downtime that comes from untested changes.&lt;/p&gt;
&lt;p&gt;The tools are also changing who can do integration work. Software developers and IT teams can now contribute meaningfully to industrial systems. The line between OT and IT continues to blur. Still, the core challenge remains the same. Someone must understand both the factory floor and the business systems. Someone must decide what runs at the edge, what belongs in the cloud, and how failures ripple across systems. The tools make integration faster and more scalable, but they don&#39;t replace the need for skilled system integrators.&lt;/p&gt;
&lt;p&gt;That&#39;s why choosing the right integrator still matters.&lt;/p&gt;
&lt;h2 id=&quot;how-to-choose-a-system-integrator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#how-to-choose-a-system-integrator&quot;&gt;How to Choose a System Integrator&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finding a system integrator isn&#39;t like hiring a contractor. You&#39;re looking for a partner who can solve problems you might not fully understand yet. Here&#39;s what to look for and what to watch out for.&lt;/p&gt;
&lt;p&gt;Start with relevant experience. An integrator who specializes in automotive won&#39;t necessarily fit food processing. The protocols, regulations, and problems are different. Look for integrators who&#39;ve worked in your industry or on similar projects. Ask for specific examples: What were the challenges? How did they solve them? What would they do differently now?&lt;/p&gt;
&lt;p&gt;Check their technical depth. Can they handle both OT and IT? Do they know the specific equipment you&#39;re using? Certifications matter (look for manufacturer certifications for your key equipment vendors) but hands-on experience matters more. Ask technical questions during the selection process. If they can&#39;t explain complex topics clearly, that&#39;s a red flag.&lt;/p&gt;
&lt;p&gt;Consider their documentation standards. When they leave, will your team understand what was built? Can someone else maintain it? Good integrators document thoroughly because they know you&#39;ll need to modify the system later. Ask to see examples of their documentation. It should include network diagrams, logic descriptions, troubleshooting guides, and clear explanations of design decisions.&lt;/p&gt;
&lt;p&gt;Look at their tooling approach. Are they building everything custom or using modern platforms that make systems easier to maintain and scale? Integrators using flow-based programming and remote management can iterate faster and handle updates without constant site visits. Ask what tools they use and why. Good integrators can explain the tradeoffs.&lt;/p&gt;
&lt;p&gt;Talk to their references (especially clients from projects two or three years old). How did the system hold up? When issues came up, how did the integrator respond? Were they available for support? Did the system adapt to changing needs? A system that works on day one but can&#39;t evolve is a liability.&lt;/p&gt;
&lt;p&gt;Pay attention to communication style in initial conversations. Do they ask good questions? Challenge your assumptions when needed? Explain clearly or hide behind jargon? A good integrator makes complex things understandable. They should be able to translate between technical teams and management, between OT and IT, between what you asked for and what you actually need.&lt;/p&gt;
&lt;p&gt;Be wary of integrators who promise everything will be easy, cheap, and fast. Good integrators set realistic expectations about timeline, budget, and risks. They identify potential problems upfront rather than discovering them halfway through the project. They explain what could go wrong and how they&#39;ll handle it.&lt;/p&gt;
&lt;p&gt;Watch for red flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reluctance to use standard protocols (proprietary solutions lock you in)&lt;/li&gt;
&lt;li&gt;No disaster recovery plan (what happens when something fails at 2 AM?)&lt;/li&gt;
&lt;li&gt;Unclear scope management (how do they handle change requests?)&lt;/li&gt;
&lt;li&gt;Limited cybersecurity knowledge (OT security is non-negotiable now)&lt;/li&gt;
&lt;li&gt;One-size-fits-all solutions (your factory isn&#39;t their last project).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beyond all these factors, you&#39;ll eventually need to talk about price. And yes, price matters, but don&#39;t let it be your only decision factor. The cheapest bid often turns into the most expensive project once you add up the delays, rework, and ongoing maintenance issues. Look for value instead: an integrator with the right expertise, proven reliability, and an approach that matches your project&#39;s complexity. Yes, they might cost more upfront. But thorough documentation, proper testing, and real support usually cost far less over five years than hiring someone who cuts corners to win the contract.&lt;/p&gt;
&lt;p&gt;Finally, remember that system integration projects rarely go exactly as planned. Equipment arrives late. Specifications change. Unexpected issues emerge during commissioning. You want a partner who&#39;ll work through problems with you, not one who disappears when things get complicated or immediately demands change orders for every small deviation. The best integrator relationships are collaborative. They bring technical expertise; you bring process knowledge. Together, you build systems that actually work for your operation.&lt;/p&gt;
&lt;h2 id=&quot;moving-forward&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#moving-forward&quot;&gt;Moving Forward&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;System integrators bridge the gap between equipment and outcomes. They take the complexity of modern manufacturing (the mix of old and new equipment, the demands for data and flexibility, the need for reliability and innovation) and turn it into working systems.&lt;/p&gt;
&lt;p&gt;The role is evolving. New tools make integration faster and more scalable. New architectures make systems more flexible and maintainable. But the fundamental challenge remains: connecting technologies that weren&#39;t designed to work together and making them serve business goals.&lt;/p&gt;
&lt;p&gt;Whether you&#39;re trying to understand what system integrators do, evaluating one for a project, or working as an integrator yourself, the core principle stays the same: good integration makes complexity disappear. The factory runs, data flows, and production hits its numbers (not by accident, but because someone built the systems that make it possible).&lt;/p&gt;
&lt;h3 id=&quot;work-with-us&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/what-is-system-integrator/#work-with-us&quot;&gt;Work With Us&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re a system integrator, FlowFuse helps you build integrations once and deploy them everywhere (across hundreds of sites, thousands of devices, without writing custom code for every project). Our platform gives you the tools to scale faster, reduce project complexity, and deliver more value to your clients.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/partners/referral-sign-up/&quot;&gt;Learn about our partner program&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/</id>
        <title>Integrating Git within Node-RED Workflow with FlowFuse</title>
        <summary>How FlowFuse connects Node-RED pipelines with Git for traceable, production-grade workflows</summary>
        <updated>2026-01-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;If you&#39;ve been using Node-RED in production, you already know the pain points. Flows get complex. Teams grow. Someone makes a change that breaks production at 2 AM. You need to roll back, but which version was working? Who approved this deployment? How do you keep your dev environment in sync with production?&lt;/p&gt;
&lt;p&gt;Traditional Node-RED doesn&#39;t have answers to these questions. But modern software development has solved these problems decades ago with version control and DevOps pipelines.&lt;/p&gt;
&lt;p&gt;That&#39;s the gap FlowFuse fills.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-devops-for-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#flowfuse%3A-devops-for-node-red&quot;&gt;FlowFuse: DevOps for Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is a platform built specifically for running Node-RED at scale. It handles deployment, management, security, team collaboration, and more so you can focus on building flows instead of managing infrastructure.&lt;/p&gt;
&lt;p&gt;Every FlowFuse can automatically create snapshots whenever flows are deployed. These snapshots let you track changes over time and roll back when needed. You can also create manual snapshots to mark important milestones.&lt;/p&gt;
&lt;p&gt;The real power comes from DevOps pipeline stages. You set up stages like development, staging, and production, then push snapshots through them. Make changes in dev, test in staging, promote to production. Everything&#39;s tracked and auditable.&lt;/p&gt;
&lt;h2 id=&quot;why-git-integration-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#why-git-integration-matters&quot;&gt;Why Git Integration Matters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We realized that many organizations already use Git as their central version control system. Their CI/CD pipelines run on Git commits. Their backup systems rely on Git repositories. Their compliance tools track changes through Git history too. To fit seamlessly into these existing workflows, Node-RED flows needed to be in Git too.&lt;/p&gt;
&lt;p&gt;That&#39;s why we built Git integration for FlowFuse. FlowFuse pipeline stages now connect directly to Git repositories. Push your snapshots to Git and pull changes back when you need them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Git integration currently supports GitHub repositories.&lt;/p&gt;
&lt;p&gt;Git integration brings several key advantages. Your flows are backed up in Git repositories alongside your other code, so if an instance is accidentally deleted, your flows remain safe and recoverable. For some companies, having all code assets version-controlled in Git repositories is a compliance requirement they must meet.&lt;/p&gt;
&lt;p&gt;Git integration works alongside FlowFuse&#39;s DevOps features—snapshots, pipelines, rollbacks—giving you the full power of both systems.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-git-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#setting-up-git-integration&quot;&gt;Setting Up Git Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s walk through connecting your FlowFuse instances to a Git repository.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse Team Account&lt;/strong&gt;: Git integration is available exclusively to Enterprise users. If you don&#39;t have a Enterprise account, visit the &lt;a href=&quot;https://flowfuse.com/pricing/&quot;&gt;FlowFuse pricing page&lt;/a&gt; or contact &lt;code&gt;sales@flowfuse.com&lt;/code&gt; to upgrade.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GitHub Account&lt;/strong&gt;: You&#39;ll need a GitHub account with permission to create repositories and generate personal access tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1%3A-create-a-github-repository&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-1%3A-create-a-github-repository&quot;&gt;Step 1: Create a GitHub Repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, set up a repository where your Node-RED flows will live:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to your GitHub account&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; icon in the top right corner and select &lt;strong&gt;New repository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Name your repository (e.g., &amp;quot;nodered-flows&amp;quot; or &amp;quot;production-flows&amp;quot;)&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Public&lt;/strong&gt; or &lt;strong&gt;Private&lt;/strong&gt; depending on your needs&lt;/li&gt;
&lt;li&gt;You can initialize with a README if you&#39;d like documentation&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create repository&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Keep this repository URL handy—you&#39;ll need it later.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-generate-a-github-personal-access-token&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-2%3A-generate-a-github-personal-access-token&quot;&gt;Step 2: Generate a GitHub Personal Access Token&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse needs permission to push and pull from your repository. GitHub uses Personal Access Tokens for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;a href=&quot;https://github.com/settings/tokens&quot;&gt;GitHub Personal Access Tokens Settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate new token&lt;/strong&gt; and select &lt;strong&gt;Generate new token (fine-grained)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Give your token a descriptive name like &amp;quot;FlowFuse Node-RED Integration&amp;quot;&lt;/li&gt;
&lt;li&gt;Set an expiration date (we recommend 90 days for security)&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Repository access&lt;/strong&gt;, choose &lt;strong&gt;Only select repositories&lt;/strong&gt; and pick which repos FlowFuse can access&lt;/li&gt;
&lt;li&gt;Under Permissions, expand &lt;strong&gt;Add permissions&lt;/strong&gt;, then locate &lt;strong&gt;Contents&lt;/strong&gt; and set it to &lt;strong&gt;Read and write&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate token&lt;/strong&gt; at the bottom&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Critical&lt;/strong&gt;: GitHub shows this token only once. Copy it immediately and store it somewhere secure. You&#39;ll paste it into FlowFuse in the next step.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-add-your-token-to-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-3%3A-add-your-token-to-flowfuse&quot;&gt;Step 3: Add Your Token to FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now let&#39;s connect FlowFuse to your GitHub account:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to your FlowFuse account&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Team Settings&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Integrations&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Find the Git integration section and click &lt;strong&gt;Add Token&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Team Settings page with the Integrations tab selected and add token button highlighted&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/team-settings-integrations.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Team Settings - Integrations tab showing Git integration options&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Give your token a name (like &amp;quot;GitHub Production Flows&amp;quot;)&lt;/li&gt;
&lt;li&gt;Paste the Personal Access Token you copied from GitHub&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Add Token dialog where users enter their GitHub Personal Access Token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-token.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding a GitHub Personal Access Token to FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Your token is now available to all Node-RED instances in your FlowFuse team.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-configure-a-pipeline-stage-for-git&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-4%3A-configure-a-pipeline-stage-for-git&quot;&gt;Step 4: Configure a Pipeline Stage for Git&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is where it comes together. You&#39;ll configure a pipeline stage to push snapshots to your Git repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: A Git repository stage needs something to push. Make sure your pipeline has at least one stage before the Git stage—typically a Node-RED instance stage. The pipeline will take snapshots from that source stage and push them to Git.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In FlowFuse, navigate to your application&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;DevOps Pipelines&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;Select the pipeline you want to add the Git stage to (or create a new one)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add Stage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the stage settings, select the Type &lt;strong&gt;Git Repository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Give the stage a name&lt;/li&gt;
&lt;li&gt;Select the token you created earlier&lt;/li&gt;
&lt;li&gt;Enter your repository URL (e.g., &lt;code&gt;https://github.com/your-username/nodered-flows.git&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Enter the snapshot file name (e.g., &lt;code&gt;flow.json&lt;/code&gt;). Leaving this blank will use the instance name. This is the name your flows will be saved as in the Git repository. When pulling changes back from Git, you must enter the exact same file name that exists in your repository to retrieve the correct flows.&lt;/li&gt;
&lt;li&gt;Specify a branch name for pushing changes (like &lt;code&gt;main&lt;/code&gt;). Make sure the branch already exists in your repository.&lt;/li&gt;
&lt;li&gt;Optionally, specify a branch name for pulling changes (like &lt;code&gt;main&lt;/code&gt;). Make sure the branch already exists in your repository.&lt;/li&gt;
&lt;li&gt;Enter a secret credential key. This can be any strong passphrase. You&#39;ll need to re-enter it when pulling changes through the DevOps pipeline in FlowFuse.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Git Repository stage configuration with fields for stage name, token, repository URL, and branch names&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/git-stage-adding.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring a Git Repository stage in a DevOps pipeline&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add Stage&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a DevOps pipeline with multiple stages including a Git repository stage successfully added&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dev-pipeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;DevOps pipeline with Git repository stage added&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-push-a-snapshot-to-git&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-5%3A-push-a-snapshot-to-git&quot;&gt;Step 5: Push a Snapshot to Git&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the Git repository stage configured in your pipeline, you&#39;re ready to push your Node-RED flows to Git.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your Node-RED instance in FlowFuse that is part of the DevOps pipeline containing the Git repository stage&lt;/li&gt;
&lt;li&gt;Make any required changes to your Node-RED flows, or keep them as-is if you want to push the current state&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;DevOps Pipelines&lt;/strong&gt; section and select the pipeline that includes the Git repository stage&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;snapshot&lt;/strong&gt; to capture the current state of your flows&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run Pipeline&lt;/strong&gt; and promote the snapshot through each stage until it reaches the Git repository stage&lt;/li&gt;
&lt;li&gt;Once the pipeline completes successfully, FlowFuse automatically commits the snapshot to the configured Git repository&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After the pipeline run finishes, you can open your Git repository and verify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A new commit containing your Node-RED flows&lt;/li&gt;
&lt;li&gt;A commit message linked to the snapshot&lt;/li&gt;
&lt;li&gt;A complete, auditable history of changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, your Node-RED workflows are version-controlled in Git and fully integrated into your existing CI/CD and DevOps processes.&lt;/p&gt;
&lt;h3 id=&quot;step-6%3A-pull-changes-from-git&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#step-6%3A-pull-changes-from-git&quot;&gt;Step 6: Pull Changes from Git&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse&#39;s Git integration works both ways. You can push flows to Git and pull changes back from Git into your Node-RED instances.&lt;/p&gt;
&lt;p&gt;The pipeline process is identical whether you&#39;re pushing or pulling—only the stage order changes. When pushing, your Git repository stage sits at the end of the pipeline. Snapshots flow from your Node-RED instance through intermediate stages and finally commit to Git. When pulling, the Git repository stage moves to the beginning. The pipeline fetches the latest commit from your configured branch, creates a snapshot, and promotes it through subsequent stages to your target instances.&lt;/p&gt;
&lt;p&gt;This bidirectional workflow solves several common challenges. Teams can commit flow changes directly to the repository and pull them into FlowFuse. You can migrate flows from other systems by committing them to Git first. Your Git repository serves as both a backup destination and a source of truth.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/how-to-integrate-node-red-with-git/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse simplifies everything about running Node-RED at scale—deployment, security, scaling, and team management. Git integration bridges the gap between FlowFuse&#39;s DevOps features and your existing development infrastructure. Your flows stay version-controlled, your team stays synchronized, and your operations stay simple.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/</id>
        <title>The Node-RED Story: How Visual Programming Escaped the Lab and Conquered Industry</title>
        <summary>From a single weekend hack to millions of deployments across homes and industry.</summary>
        <updated>2026-01-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In late 2011, Nick O&#39;Leary was a &amp;quot;plumber&amp;quot; of the digital age. As part of IBM&#39;s Emerging Technology Group, he spent his days building experimental projects that pushed the boundaries of what connected systems could do. But there was a problem: for every new experiment, he found himself writing the same boilerplate code over and over — the tedious &amp;quot;wiring&amp;quot; work needed to make different systems talk to each other.&lt;/p&gt;
&lt;h2 id=&quot;the-birth-of-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-birth-of-node-red&quot;&gt;The Birth of Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The frustration was mounting. Each new project at IBM&#39;s Emerging Technology lab meant rewriting integration code from scratch. Nick knew there had to be a better way.&lt;/p&gt;
&lt;p&gt;On a &amp;quot;wet January day in 2013,&amp;quot; Nick decided to try something new. He wanted a way to visualize mapping messages across an MQTT infrastructure. He turned to Node.js — then a relatively new technology — as the foundation.&lt;/p&gt;
&lt;p&gt;Over a single weekend, he built a rough prototype that allowed him to drag boxes and draw wires instead of writing endless integration code. When he showed it to his colleague Dave Conway-Jones on Monday morning, Dave’s response was immediate and world-changing: &amp;quot;Go on then.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dave Conway-Jones and Nick O&#39;Leary, co-creators of Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nick-and-dave.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dave and Nick&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The name was a light-hearted play on words. &amp;quot;Node&amp;quot; reflected the Node.js runtime and the flow-based model, while &amp;quot;RED&amp;quot; was a cheeky nod to &amp;quot;Code Red.&amp;quot; While some later suggested it stood for &amp;quot;Rapid Event Developer,&amp;quot; Nick and Dave never felt the need to formalize it. It was simply a vibrant alternative to the &amp;quot;Big Blue&amp;quot; corporate standard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Early version of Node-RED interface showing visual flow-based programming with connected nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/early-node-red-screenshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Early Node-RED Screenshot&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Those two words meant everything. Dave didn&#39;t just approve — he joined in. Together, they started refining the tool, adding features, testing it on real IBM projects. What began as Nick&#39;s weekend hack became their shared mission. Within weeks, they had transformed a rough prototype into something that actually worked in production. The tool that was supposed to save Nick time on one project was now saving their entire team hours every week.&lt;/p&gt;
&lt;p&gt;Node-RED offered something different: freedom. Drag boxes. Connect wires. Make anything talk to anything. No permission required.&lt;/p&gt;
&lt;h2 id=&quot;the-public-spark&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-public-spark&quot;&gt;The Public Spark&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The transition from a lab tool to a public project wasn&#39;t a corporate rollout; it was a grassroots explosion. By late 2013, Nick and Dave had seen enough: Node-RED was too useful to keep locked inside the walls of IBM.&lt;/p&gt;
&lt;h3 id=&quot;the-first-commit%3A-september-5%2C-2013&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-first-commit%3A-september-5%2C-2013&quot;&gt;The First Commit: September 5, 2013&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The public story of Node-RED began with a push, not a press release. On &lt;strong&gt;September 5, 2013&lt;/strong&gt;, the first code was uploaded to GitHub. It was a &amp;quot;soft launch&amp;quot; — a way to see if the world actually needed a visual tool for &amp;quot;wiring&amp;quot; the Internet of Things. Within weeks, the community responded with an intensity that caught even the creators by surprise.&lt;/p&gt;
&lt;h3 id=&quot;the-%22workshop%22-moment%3A-wuthering-bytes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-%22workshop%22-moment%3A-wuthering-bytes&quot;&gt;The &amp;quot;Workshop&amp;quot; Moment: Wuthering Bytes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first external validation happened just a week after the GitHub release at the &lt;strong&gt;Wuthering Bytes&lt;/strong&gt; technology festival. After Nick gave a brief, unprepared lightning talk, he walked into a workshop the following day and was stunned to see &lt;strong&gt;Node-RED on every single screen.&lt;/strong&gt; A workshop facilitator had discovered the code on GitHub just days earlier and immediately scrapped his original plan. He realized that instead of teaching students how to troubleshoot line-by-line syntax, he could use Node-RED to let them actually &lt;em&gt;build&lt;/em&gt; something. In thirty minutes, the class had achieved what usually took an entire day. It was the first time Nick saw people he had never met using his creation to solve real problems.&lt;/p&gt;
&lt;h3 id=&quot;the-london-node.js-user-group-(lnug)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-london-node.js-user-group-(lnug)&quot;&gt;The London Node.js User Group (LNUG)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While the hardware community was the first to adopt it, the &lt;strong&gt;London Node.js User Group (LNUG)&lt;/strong&gt; was where the project faced its first true technical trial. Standing before a room of seasoned JavaScript developers, Nick had a 30-minute slot to prove that Node-RED wasn&#39;t just a visual toy — it was a powerful tool built on the very event-driven architecture they loved. The talk was a massive success, generating immediate buzz across social media and solidifying Node-RED’s reputation within the developer community.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;CF7BGDj2_G8&quot; params=&quot;rel=0&amp;start=1740&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;LNUG October 2013: Node-RED - Nick O&#39;Leary&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-big-stage%3A-thingmonk-2013&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-big-stage%3A-thingmonk-2013&quot;&gt;The Big Stage: ThingMonk 2013&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While the September meetups provided the spark, &lt;strong&gt;ThingMonk on December 3, 2013&lt;/strong&gt;, was the &amp;quot;Big Bang.&amp;quot; This was the first major professional and industrial stage for Node-RED. It was here that the industry elite — the architects of the &amp;quot;Internet of Things&amp;quot; — realized that Node-RED was the answer to the &amp;quot;glorious mess&amp;quot; of incompatible protocols.&lt;/p&gt;
&lt;p&gt;In his presentation, &amp;quot;Wiring the Internet of Things,&amp;quot; Nick showed that visual programming wasn&#39;t just a shortcut for beginners; it was a professional-grade solution for the most complex integration problems on the planet.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;zUoCJb0jzuo&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;ThingMonk 2013: Wiring The Internet of Things&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;2014%3A-proving-the-concept&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#2014%3A-proving-the-concept&quot;&gt;2014: Proving the Concept&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If 2013 was the spark, 2014 was the foundation. This was the year Node-RED moved from a lab experiment to a professional tool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IBM&#39;s launch of Bluemix&lt;/strong&gt; (now IBM Cloud) marked a pivotal moment — Node-RED became a flagship starter app, validating that visual programming could power enterprise-grade cloud applications. The year also saw multiple major version releases that enhanced the platform&#39;s capabilities.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED featured as a flagship starter app on IBM Bluemix in 2014&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ibm-bluemix.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED featured as a flagship starter app on IBM Bluemix in 2014&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;During this period, Nick took the project on the road — speaking at conferences and meetups to actively build the community around Node-RED. A major milestone came at QCon London 2014, a moment Nick has often described as especially meaningful. The talk marked a turning point, demonstrating to the professional software industry that visual programming could be a serious, scalable solution for complex data integration.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Nick O’Leary presenting Node-RED at QCon London 2014&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Q-CON-2014.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Nick O’Leary presenting Node-RED at QCon London 2014&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-explosion%3A-the-raspberry-pi-milestone&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-explosion%3A-the-raspberry-pi-milestone&quot;&gt;The Explosion: The Raspberry Pi Milestone&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By November 2015, Node-RED was officially integrated into the Raspbian Jessie image, marking its transition from a manual install to a core component of the Raspberry Pi ecosystem. The &lt;a href=&quot;https://www.raspberrypi.com/news/latest-raspbian-update/&quot;&gt;announcement was made by Simon Long&lt;/a&gt;, the Raspberry Pi Foundation&#39;s UX Engineer, who detailed the update in a blog post on December 2, 2015. This milestone meant that millions of $35 computers suddenly shipped with a visual programming tool built specifically for the &amp;quot;Internet of Things,&amp;quot; sitting prominently in the application menu alongside educational staples like Scratch and Python.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Raspbian Jessie desktop menu showing Node-RED included by default with Scratch and Python on Raspberry Pi&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-on-pi.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Raspbian Jessie desktop menu showing Node-RED included by default with Scratch and Python on Raspberry Pi&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The impact was immediate and massive. Students learning to code on Raspberry Pi discovered Node-RED next to Python. Hobbyists building weekend projects found it pre-installed. Educators teaching IoT concepts had a visual tool ready to use. What had required hunting through forums and installation guides was now just a click away in the menu. The barrier to entry dropped to zero, and the community exploded.&lt;/p&gt;
&lt;p&gt;Within months, Node-RED flows for Raspberry Pi projects flooded online forums. Home automation guides assumed you had it installed. The &amp;quot;install Node-RED&amp;quot; step disappeared from tutorials — it was just there. This wasn&#39;t just about convenience. It was about legitimacy. Being bundled with Scratch and Python signaled that Node-RED wasn&#39;t a niche hack — it was essential infrastructure for the IoT era.&lt;/p&gt;
&lt;h2 id=&quot;a-home-for-the-future%3A-the-openjs-foundation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#a-home-for-the-future%3A-the-openjs-foundation&quot;&gt;A Home for the Future: The OpenJS Foundation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By 2016, Node-RED had outgrown its &amp;quot;side project&amp;quot; status at IBM. To ensure the tool remained open and vendor-neutral, &lt;a href=&quot;https://nodered.org/blog/2016/10/17/js-foundation&quot;&gt;IBM moved Node-RED into the newly formed JS Foundation&lt;/a&gt; (which merged in 2019 to become the OpenJS Foundation) as a founding project.&lt;/p&gt;
&lt;p&gt;This was a pivotal moment for industrial adoption. By moving the project to a neutral foundation, Node-RED was no longer just an &amp;quot;IBM tool&amp;quot; — it became a public utility. Large-scale industrial players like Hitachi and Siemens could now contribute to the code and build their own products on top of it without fear of &amp;quot;vendor lock-in.&amp;quot; It signaled that Node-RED was a stable, world-class piece of software infrastructure, governed by the same community standards as jQuery and Node.js.&lt;/p&gt;
&lt;p&gt;The foundation move unlocked something crucial: trust at scale. When a Fortune 500 manufacturer evaluates tools, vendor neutrality isn&#39;t optional — it&#39;s mandatory. The OpenJS Foundation gave Node-RED the governance structure, intellectual property protections, and community oversight that enterprises require. Companies that would never bet their production lines on an IBM internal tool could now build on Node-RED with confidence. The path from hobbyist workshops to factory floors was open.&lt;/p&gt;
&lt;h2 id=&quot;the-community-takes-over&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-community-takes-over&quot;&gt;The Community Takes Over&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The community didn&#39;t just use Node-RED — they built it. By 2023, the library contained over 4,300 nodes. Every new smart device gets a Node-RED node within weeks. Every protocol got wrapped. Forums filled with shared flows. Someone in Germany would solve a lighting problem at 2 AM, share the solution, and someone in California would adapt it for their garage door an hour later.&lt;/p&gt;
&lt;p&gt;This wasn&#39;t just a user base — it was a movement. Makers, hobbyists, and tinkerers around the world were solving problems and sharing solutions freely. The barrier to contribution was low — anyone could create a node and publish it. The barrier to adoption was even lower — anyone could install a node with a single click.&lt;/p&gt;
&lt;p&gt;The community&#39;s creativity extended across domains. Nodes were built for popular platforms, industrial protocols, cloud services, databases, messaging systems, AI services, and thousands of integrations beyond. If a technology existed, someone had already made it work in Node-RED.&lt;/p&gt;
&lt;p&gt;But something unexpected was happening beneath the surface. While the community shared home automation flows in forums, engineers in factories were quietly watching. They saw the same drag-and-drop simplicity that connected smart lights could connect production equipment. They saw the protocol-agnostic approach that worked for hobbyists could work for industrial systems. They saw a tool that both IT and operations teams could actually understand.&lt;/p&gt;
&lt;p&gt;The movement that began in living rooms was about to reach factory floors.&lt;/p&gt;
&lt;h2 id=&quot;the-bridge-nobody-planned&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-bridge-nobody-planned&quot;&gt;The Bridge Nobody Planned&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The movement reached Hitachi&#39;s factory floors in a way nobody anticipated. Node-RED emerged as a crucial communication tool bridging the gap between IT and factory engineers. Its intuitive interface allowed the entire flow to be visible on screen, facilitating discussions and collaborative efforts seamlessly.&lt;/p&gt;
&lt;p&gt;For decades, IT and OT spoke different languages. IT managed databases and networks. OT ran machines and production lines. They needed each other but couldn&#39;t understand each other. Node-RED gave them a shared vocabulary—visual flows that both sides could read.&lt;/p&gt;
&lt;p&gt;A factory engineer could build a flow reading data from a Modbus PLC. An IT engineer could look at that same flow and immediately understand what it did. No translation needed. The same visual language that connected smart home devices was now connecting industrial equipment to enterprise systems.&lt;/p&gt;
&lt;p&gt;The movement had arrived in the industry. And it brought its community-driven, protocol-agnostic approach with it.&lt;/p&gt;
&lt;h2 id=&quot;the-numbers-prove-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#the-numbers-prove-it&quot;&gt;The Numbers Prove It&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nodered.org/about/community/survey/2019/&quot;&gt;The 2019&lt;/a&gt; survey captured the movement mid-expansion: 31.5% used it in manufacturing, and 24% had created PLC applications. Home automation remained strong, but the industry was already significant.&lt;/p&gt;
&lt;p&gt;By &lt;a href=&quot;https://nodered.org/about/community/survey/2023/&quot;&gt;2023&lt;/a&gt;, the industrial footprint had solidified. Manufacturing remained the second largest industry at 40%, up from 31.5%. Just over 40% now use Node-RED professionally. Home automation usage held steady at 70% — both sectors thriving, not competing.&lt;/p&gt;
&lt;p&gt;The protocols revealed the depth of industrial adoption. MQTT and HTTP dominated both sectors. But Modbus and OPC-UA — industrial protocols — saw significant growth. These weren&#39;t hobbyists experimenting. These were engineers connecting real production equipment.&lt;/p&gt;
&lt;p&gt;The movement had conquered two worlds simultaneously.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-conquering-industrial-iot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#flowfuse%3A-conquering-industrial-iot&quot;&gt;FlowFuse: Conquering Industrial IoT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By 2021, the challenge had shifted. Node-RED worked brilliantly for individual developers, but enterprises needed more: how do you scale it across tens of thousands of factory instances? How do you secure it? How do you make teams collaborate on flows without stepping on each other&#39;s work? To solve these problems, Nick founded FlowFuse (formerly FlowForge).&lt;/p&gt;
&lt;p&gt;But a technical revolution needs both an inventor and an architect. In January 2022, Zeger-Jan van de Weg (ZJ) joined as CEO. Drawing on his experience as an early GitLab employee, ZJ knew how to turn a successful open-source project into an enterprise-grade platform. While Nick continues to guide the technical direction as CTO, ZJ leads the effort to scale industrial automation for Fortune 500 companies.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Nick and ZJ&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/zj-and-nick.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Nick and ZJ&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Together, they have raised $14.5 million to build the infrastructure enterprises demand. With this funding, they assembled a talented team spanning engineering, product, customer success, marketing, sales, and community, each member contributing their unique expertise to drive FlowFuse&#39;s growth across every aspect of the business.&lt;/p&gt;
&lt;p&gt;Between 2021 and 2025, FlowFuse evolved into a full industrial ecosystem through deliberate focus on operational maturity. The journey began with team collaboration and scaling — introducing version control, team permissions, and DevOps pipelines that let engineering teams work together on flows like software projects, then deploy updates across thousands of remote Node-RED instances with discipline. With collaboration and scale established, the focus shifted to enterprise security, adding SSO, RBAC, and SOC 2 compliance to meet strict governance requirements. Next came infrastructure independence, integrating a built-in MQTT broker and FlowFuse Tables to reduce reliance on external services. By 2025, as AI began reshaping industry, FlowFuse entered the intelligence era with MCP nodes, and FlowFuse Expert — an AI that converts plain-English industrial problems directly into working Node-RED flows.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s mission went beyond enterprise features. It invested continuously in Node-RED core development and community sustainability. When the original &lt;a href=&quot;https://discourse.nodered.org/t/announcement-node-red-dashboard-v1-deprecation-notice/89006/2&quot;&gt;Node-RED Dashboard was deprecated&lt;/a&gt;, FlowFuse rebuilt &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0&lt;/a&gt; from the ground up.&lt;/p&gt;
&lt;p&gt;That commitment extended to the ecosystem itself. Through the &lt;a href=&quot;https://flowfuse.com/blog/2025/07/certified-nodes-v2/&quot;&gt;Certified Nodes program&lt;/a&gt;, FlowFuse identifies critical community nodes and subjects them to rigorous security and quality testing. To ensure long-term reliability, FlowFuse supports maintainers financially or assumes maintenance responsibility — an approach aligned with the expectations of large industrial organizations.&lt;/p&gt;
&lt;p&gt;Education and community came next. FlowFuse launched &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;Node-RED Academy&lt;/a&gt;, the first official Node-RED Academy offering Node-RED certification, providing a clear path from learning flows to building production-ready systems. This was followed by major investment in &lt;a href=&quot;https://discourse.nodered.org/t/node-red-survey-shaping-the-future-of-node-reds-user-experience/98346/95&quot;&gt;modernizing the Node-RED editor UI&lt;/a&gt; through an open, community-driven process. The journey culminated in the Node-RED Conference, bringing together over 1,000 live attendees worldwide and transforming a distributed user base into a connected industrial community.&lt;/p&gt;
&lt;p&gt;Five years into its journey, FlowFuse stands as a rare example of open source scaling into industrial reality without losing its soul. What started as a way to operate Node-RED at scale is now a production platform deployed in some of the world&#39;s largest factories — increasingly taking on responsibilities once dominated by legacy industrial platforms. It demonstrates that when community stewardship, engineering rigor, and long-term vision align, open source can form the backbone of modern industrial systems.&lt;/p&gt;
&lt;p&gt;This vision has translated into explosive market adoption, with the company multiplying its annual recurring revenue and customer base by nearly 5x in the last year alone.&lt;/p&gt;
&lt;h2 id=&quot;why-it-succeeded&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#why-it-succeeded&quot;&gt;Why It Succeeded&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED won because it was simple when everyone else was complicated.&lt;/p&gt;
&lt;p&gt;The smart home industry sold subscriptions and proprietary hubs. Industrial automation sold certifications and consulting contracts. Both pretended connecting systems required expertise only they could provide.&lt;/p&gt;
&lt;p&gt;Node-RED proved them wrong. Drag a box. Draw a line. Done.&lt;/p&gt;
&lt;p&gt;The same principles work everywhere. A homeowner connecting a thermostat to weather data uses the exact concepts an engineer uses connecting factory equipment to a data lake. Input. Logic. Output. The scale changes. The principles don&#39;t.&lt;/p&gt;
&lt;p&gt;The visual interface removed the gatekeepers. You didn&#39;t need to understand APIs or write integration code. You could see the logic, understand it, and modify it — all on one screen. When both the factory floor worker and the IT manager can look at the same flow and grasp what it does, you&#39;ve eliminated the translation layer that created vendor dependency.&lt;/p&gt;
&lt;h2 id=&quot;today-and-tomorrow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#today-and-tomorrow&quot;&gt;Today and Tomorrow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today, Node-RED spans from living rooms to factory floors. FlowFuse has made it enterprise-ready.&lt;/p&gt;
&lt;p&gt;Home users still rely on Node-RED to make incompatible smart devices work together. But FlowFuse has transformed industrial adoption—turning a powerful tool into production infrastructure with fleet management, enterprise security, and DevOps pipelines that Fortune 500 companies trust.&lt;/p&gt;
&lt;p&gt;The scale is substantial. Manufacturing plants run FlowFuse across thousands of remote sites. Energy companies depend on it for critical infrastructure monitoring. What started as visual programming for hobbyists now handles mission-critical operations where downtime costs millions per hour.&lt;/p&gt;
&lt;p&gt;The momentum continues building. FlowFuse is pushing Node-RED into new territory — AI-powered flow generation, advanced analytics, and capabilities that didn&#39;t exist two years ago. As AI reshapes manufacturing and operations, Node-RED is positioned at the center of that transformation.&lt;/p&gt;
&lt;p&gt;The revolution that began in living rooms and reached factory floors is entering its next phase.&lt;/p&gt;
&lt;h2 id=&quot;final-note&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2026/01/node-red-history-community-industrial-iot-flowfuse/#final-note&quot;&gt;Final Note&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Writing this reminded me why I fell in love with Node-RED. But the real story isn&#39;t in these words — it&#39;s unfolding right now in someone&#39;s garage, on a factory floor, in a student&#39;s first &amp;quot;it works!&amp;quot; moment.&lt;/p&gt;
&lt;p&gt;What amazes me most is the community&#39;s generosity. People don&#39;t just solve problems — they share them, celebrate each other&#39;s wins. Curiosity matters more than credentials. &amp;quot;I don&#39;t know, but let&#39;s figure it out together&amp;quot; is the standard response.&lt;/p&gt;
&lt;p&gt;If this story touched you, please share it. Someone out there might need the reminder that the impossible is usually just the not-yet-possible.&lt;/p&gt;
&lt;p&gt;Thank you for reading, and happy New Year!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/what-is-mttf/</id>
        <title>Mean Time to Failure (MTTF): Formula, Calculation, MTTF vs MTBF vs MTTR, and More</title>
        <summary>Understanding equipment reliability and predicting failure patterns</summary>
        <updated>2025-12-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/what-is-mttf/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;When a critical motor bearing assembly fails after just 6 months—half its rated lifespan—maintenance teams face a fundamental question: &amp;quot;How long should this component actually last?&amp;quot;&lt;/p&gt;
&lt;p&gt;Mean Time to Failure (MTTF) provides the answer. It measures the average operational lifetime of non-repairable components before permanent failure, enabling data-driven decisions about replacement timing, spare parts inventory, and component selection.&lt;/p&gt;
&lt;p&gt;MTTF emerged as a core reliability engineering metric in the 1950s during the development of military and aerospace reliability theory. Today, it remains essential across industries where component reliability determines operational success—from semiconductor manufacturing to data centers to industrial automation.&lt;/p&gt;
&lt;p&gt;This guide explains what MTTF measures, how to calculate it correctly with real examples, how it differs from related metrics, and how to use MTTF data for strategic maintenance planning.&lt;/p&gt;
&lt;h2 id=&quot;what-is-mean-time-to-failure-(mttf)%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#what-is-mean-time-to-failure-(mttf)%3F&quot;&gt;What is Mean Time to Failure (MTTF)?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mean Time to Failure (MTTF) is a reliability metric that measures &lt;strong&gt;the average operating time of a non-repairable component before it fails permanently&lt;/strong&gt;. Once the component fails, it is &lt;strong&gt;replaced, not repaired&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;MTTF is commonly used for items such as light bulbs, batteries, sealed bearings, hard drives, electronic modules, and disposable filters. It helps teams understand how long a part typically lasts under normal operating conditions, enabling better planning for replacements, spare parts management, and reduction of unexpected downtime.&lt;/p&gt;
&lt;p&gt;MTTF is a core concept in reliability engineering and is widely used in maintenance planning, lifecycle cost analysis, and dependability studies. It is formally supported by industry standards such as &lt;strong&gt;&lt;a href=&quot;https://www.sre.org/mil-hdbk-217-the-perceived-standard/&quot;&gt;MIL-HDBK-217&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href=&quot;https://standards.ieee.org/ieee/1413/3764/&quot;&gt;IEEE Standard 1413&lt;/a&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;a href=&quot;https://webstore.iec.ch/en/publication/1294&quot;&gt;IEC 60300-3-1&lt;/a&gt;&lt;/strong&gt;, which provide guidance on reliability and dependability analysis across the equipment life cycle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: MTTF represents a statistical average—some components will fail earlier while others last longer. Use it for planning and forecasting, not for predicting exact failure times of individual components.&lt;/p&gt;
&lt;h2 id=&quot;mean-time-to-failure-(mttf)-formula&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#mean-time-to-failure-(mttf)-formula&quot;&gt;Mean Time to Failure (MTTF) Formula&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The MTTF calculation is straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MTTF = Total Operating Time / Number of Failures
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Total Operating Time&lt;/strong&gt; is the sum of all hours every unit ran before failing. &lt;strong&gt;Number of Failures&lt;/strong&gt; is how many units failed permanently and were replaced (not repaired).&lt;/p&gt;
&lt;h3 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#example&quot;&gt;Example&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You have 50 light bulbs. Ten bulbs burn out after 8,000 hours (that&#39;s 80,000 total hours). Fifteen more fail at 10,000 hours (150,000 hours). The remaining 25 bulbs last 12,000 hours each (300,000 hours). Add it all up and you get 530,000 hours across 50 bulbs.&lt;/p&gt;
&lt;p&gt;MTTF = 530,000 / 50 = &lt;strong&gt;10,600 hours&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This means on average, each bulb lasts 10,600 hours before it fails.&lt;/p&gt;
&lt;h3 id=&quot;quick-shortcuts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#quick-shortcuts&quot;&gt;Quick Shortcuts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If all your components run the same amount of time before the test ends, you can use this shortcut: multiply the number of units by hours run, then divide by failures observed.&lt;/p&gt;
&lt;p&gt;The failure rate is simply the inverse of MTTF. If MTTF is 10,000 hours, your failure rate is 0.0001 failures per hour, which means you expect 1 failure every 10,000 hours.&lt;/p&gt;
&lt;h3 id=&quot;what-this-formula-assumes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#what-this-formula-assumes&quot;&gt;What This Formula Assumes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The basic MTTF formula works when you&#39;re tracking non-repairable parts, failures occur randomly during their normal lifespan, and operating conditions remain roughly consistent. You also need enough failures to make the average meaningful—ideally 30 or more data points.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When basic MTTF doesn&#39;t apply&lt;/strong&gt;: If you have components still running at the end of your observation period, or if failure patterns follow a bathtub curve (high early failures, stable middle period, increasing wear-out failures), you&#39;ll need advanced statistical methods like Weibull analysis or censored data techniques.&lt;/p&gt;
&lt;h2 id=&quot;how-to-calculate-mean-time-to-failure-(mttf)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#how-to-calculate-mean-time-to-failure-(mttf)&quot;&gt;How to Calculate Mean Time to Failure (MTTF)&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;example-1%3A-data-center-hard-drives&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#example-1%3A-data-center-hard-drives&quot;&gt;Example 1: Data Center Hard Drives&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A data center operates 100 identical hard drives. Over 18 months of operation, they track which drives fail and need replacement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Month 6:&lt;/strong&gt; 3 drives fail after 4,380 hours each = 13,140 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Month 9:&lt;/strong&gt; 5 drives fail after 6,570 hours each = 32,850 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Month 12:&lt;/strong&gt; 4 drives fail after 8,760 hours each = 35,040 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Month 15:&lt;/strong&gt; 6 drives fail after 10,950 hours each = 65,700 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Month 18:&lt;/strong&gt; 7 drives fail after 13,140 hours each = 91,980 hours&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total operating time = 238,710 hours&lt;br /&gt;
Total failures = 25 drives&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MTTF = 238,710 / 25 = 9,548 hours&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This tells the data center they can expect each hard drive to last roughly 9,548 hours (just over 1 year). The remaining 75 drives are still running, so the actual MTTF might be higher, but this gives them a working estimate for planning replacements and maintaining spare inventory.&lt;/p&gt;
&lt;h3 id=&quot;example-2%3A-manufacturing-plant-conveyor-belts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#example-2%3A-manufacturing-plant-conveyor-belts&quot;&gt;Example 2: Manufacturing Plant Conveyor Belts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A factory runs 20 conveyor lines, each with identical drive belts. The maintenance team tracks belt failures over 2 years:&lt;/p&gt;
&lt;p&gt;All 20 belts start fresh. After 8,000 hours of operation, 4 belts have failed. After 12,000 hours, 6 more fail. After 16,000 hours, another 5 fail. The remaining 5 belts are still running at the 2-year mark (17,520 hours).&lt;/p&gt;
&lt;p&gt;Simplified calculation using all belts (including those still running):&lt;/p&gt;
&lt;p&gt;Total time = 20 belts × 17,520 hours = 350,400 hours&lt;br /&gt;
Total failures = 15 belts&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MTTF = 350,400 / 15 = 23,360 hours&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The plant now knows these belts typically last about 23,360 hours (roughly 2.7 years in continuous operation). They can schedule preventive replacements at around 20,000 hours to avoid unexpected breakdowns during production runs.&lt;/p&gt;
&lt;h2 id=&quot;common-calculation-mistakes-to-avoid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#common-calculation-mistakes-to-avoid&quot;&gt;Common Calculation Mistakes to Avoid&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the most common mistakes when calculating MTTF is confusing calendar time with actual operating hours. A component that runs only part of the day will accumulate operating hours much more slowly than calendar time passes, so it’s critical to measure true runtime rather than elapsed days or months. Another frequent error is including repaired equipment in MTTF calculations. If a component is fixed and returned to service, it belongs in MTBF calculations, not MTTF, which only applies to items that are permanently replaced after failure.&lt;/p&gt;
&lt;p&gt;Small sample sizes also lead to misleading results. Calculating MTTF from just a few failures can produce numbers that fluctuate widely and don’t reflect real performance. In practice, at least 20 to 30 failures are needed to produce meaningful averages, with larger datasets providing more reliable insight. Operating conditions are another major source of error. The same component can have very different lifespans depending on factors like temperature, dust, vibration, and load, so MTTF values should always be compared under similar conditions.&lt;/p&gt;
&lt;p&gt;Finally, MTTF is often misunderstood as a guaranteed lifespan. It is only an average. Some components will fail much earlier than the MTTF value, while others will last significantly longer. Maintenance planning should account for this natural variation instead of treating MTTF as a minimum life expectancy.&lt;/p&gt;
&lt;h2 id=&quot;difference-between-mttf%2C-mtbf%2C-and-mttr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#difference-between-mttf%2C-mtbf%2C-and-mttr&quot;&gt;Difference Between MTTF, MTBF, and MTTR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These three acronyms measure fundamentally different aspects of reliability:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;th&gt;Use For&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MTTF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Average time until permanent failure&lt;/td&gt;
&lt;td&gt;Non-repairable items replaced when they fail&lt;/td&gt;
&lt;td&gt;Light bulbs, batteries, hard drives, sealed bearings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MTBF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Average time between repair events&lt;/td&gt;
&lt;td&gt;Repairable systems fixed and returned to service&lt;/td&gt;
&lt;td&gt;Motors, pumps, HVAC systems, vehicles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MTTR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Average time to complete repairs&lt;/td&gt;
&lt;td&gt;Any equipment requiring repair&lt;/td&gt;
&lt;td&gt;All repairable systems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The key distinction&lt;/strong&gt;: MTTF applies when you discard and replace it. MTBF applies when you fix it and keep using it. MTTR tells you how long the fixing takes.&lt;/p&gt;
&lt;h3 id=&quot;calculation-formulas&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#calculation-formulas&quot;&gt;Calculation Formulas&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MTTF&lt;/strong&gt; = Total operating time ÷ Number of permanent failures&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MTBF&lt;/strong&gt; = Total operating time ÷ Number of repair events (excluding repair time)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MTTR&lt;/strong&gt; = Total repair time ÷ Number of repairs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A facility might track MTTF for LED bulbs in their fixtures (replace when burned out) while tracking MTBF for the fixtures themselves (repair when they fail). Both metrics serve different planning purposes.&lt;/p&gt;
&lt;h2 id=&quot;where-to-find-reliable-mttf-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#where-to-find-reliable-mttf-data&quot;&gt;Where to Find Reliable MTTF Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturer datasheets are a useful starting point, but they should not be treated as definitive. Published MTTF values are usually measured under controlled laboratory conditions with clean environments, ideal installation, stable temperatures, and moderate loads. Real operating environments are rarely this consistent, so actual component life in the field is often shorter or more variable than datasheet values suggest.&lt;/p&gt;
&lt;p&gt;Industry reliability databases provide more realistic benchmarks. Standards such as &lt;a href=&quot;https://www.iso.org/standard/64076.html&quot;&gt;ISO 14224&lt;/a&gt; compile failure and maintenance data from hundreds of similar facilities, offering reference values that reflect real-world operating conditions rather than ideal test scenarios. These benchmarks are helpful for comparison, but they still represent averages across many sites and may not fully match your specific environment.&lt;/p&gt;
&lt;p&gt;The most reliable MTTF data comes from your own facility. By tracking installation dates and failure times, you can build site-specific reliability data that reflects your actual loads, temperatures, maintenance practices, and environmental conditions. After collecting data from 20 to 30 failures, your internal MTTF values will often be more accurate and actionable than any external source.&lt;/p&gt;
&lt;h2 id=&quot;using-mttf-for-better-maintenance-planning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#using-mttf-for-better-maintenance-planning&quot;&gt;Using MTTF for Better Maintenance Planning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MTTF delivers the most value when it supports proactive maintenance decisions rather than reactive repairs. When using MTTF for maintenance planning, the objective is to replace components before failures disrupt production. For example, if a component typically fails around 20,000 operating hours, scheduling replacement at 15,000 hours during planned maintenance windows can prevent unexpected breakdowns and emergency interventions. Replacing parts slightly early is often far less costly than absorbing unplanned downtime.&lt;/p&gt;
&lt;p&gt;MTTF also plays a critical role in spare parts optimization, particularly in manufacturing and industrial automation environments where many identical components operate continuously across multiple machines. By estimating expected failures per year based on operating hours and installed quantities, maintenance teams can stock enough spares to meet short-term demand without tying up excessive working capital. Even modest improvements in MTTF-based inventory planning can significantly reduce both downtime risk and excess inventory.&lt;/p&gt;
&lt;p&gt;Supplier selection becomes more objective when MTTF data is used instead of relying solely on datasheet claims. In real-world maintenance planning scenarios, teams can compare components based on total cost per operating hour rather than purchase price alone. A higher-priced component with a longer operating life may ultimately be more economical once labor costs, downtime impact, and replacement frequency are considered.&lt;/p&gt;
&lt;p&gt;Finally, MTTF helps reveal the true cost drivers within maintenance budgets across manufacturing and industrial automation systems. By combining replacement costs, downtime impact, and failure frequency, teams can identify which components contribute most to annual maintenance spend. Incremental improvements in component reliability often translate into substantial cost savings while also improving overall equipment availability.&lt;/p&gt;
&lt;h2 id=&quot;when-mttf-isn&#39;t-the-right-metric&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#when-mttf-isn&#39;t-the-right-metric&quot;&gt;When MTTF Isn&#39;t the Right Metric&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MTTF has limitations. Don&#39;t use it when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Equipment gets repaired, not replaced&lt;/strong&gt; - Use MTBF instead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Failure patterns show wear-out&lt;/strong&gt; - Components with bathtub curves (high early failures, then stable, then increasing wear-out failures) need Weibull analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need real-time reliability&lt;/strong&gt; - MTTF describes past performance; it doesn&#39;t predict when the next specific unit will fail&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety-critical applications&lt;/strong&gt; - Statistical averages aren&#39;t appropriate for systems where a single failure could cause injury or environmental harm. Use fault tree analysis or failure mode effects analysis instead&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bottom-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-mttf/#bottom-line&quot;&gt;Bottom Line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Stop guessing when parts will fail. Start tracking installation dates and failure times today. After 20-30 failures, you&#39;ll have better data than any manufacturer spec sheet—data that reflects your actual operating conditions, not laboratory ideals.&lt;/p&gt;
&lt;p&gt;Use that data to schedule replacements during planned downtime rather than waiting for 2am emergency breakdowns. Stock the right number of spares—not too many tying up working capital, not too few forcing expedited shipping and production delays. Compare suppliers based on actual performance in your facility, not who&#39;s cheapest on paper.&lt;/p&gt;
&lt;p&gt;The math is straightforward: unplanned breakdowns cost 3-5x more than scheduled replacements when you factor in overtime labor, rush parts shipping, and lost production. MTTF transforms reactive firefighting into predictable maintenance.&lt;/p&gt;
&lt;p&gt;Your facility is unique. Your conditions, loads, and environment create a reliability profile unlike any other operation. The only MTTF numbers that truly matter are the ones you measure yourself.&lt;/p&gt;
&lt;p&gt;As your equipment base grows, manual tracking becomes cumbersome. &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; automates this by connecting to &lt;a href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/&quot;&gt;PLCs&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;SCADA&lt;/a&gt; systems, &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;MES&lt;/a&gt; platforms, and your CMMS—pulling operating hours directly from equipment through industrial protocols like &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Modbus&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;OPC UA&lt;/a&gt;, and &lt;a href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/&quot;&gt;EtherNet/IP&lt;/a&gt;, then capturing failure events to recalculate MTTF in real-time across your entire facility.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/what-is-plc/</id>
        <title>What Is a PLC (Programmable Logic Controller)? What It Does, How It Works, and Where It’s Used</title>
        <summary>How Dick Morley&#39;s New Year&#39;s Day Hangover Changed Manufacturing Forever</summary>
        <updated>2025-12-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/what-is-plc/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;&lt;em&gt;&lt;strong&gt;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.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On New Year&#39;s Day 1968, &lt;a href=&quot;https://en.wikipedia.org/wiki/Dick_Morley&quot;&gt;Dick Morley&lt;/a&gt;, 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 &amp;quot;a wicked headache,&amp;quot; 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.&lt;/p&gt;
&lt;p&gt;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&#39;s Modicon 084 replaced 20,000 mechanical components with a single box that could be reprogrammed in hours.&lt;/p&gt;
&lt;p&gt;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&#39;s a &lt;a href=&quot;https://www.mordorintelligence.com/industry-reports/programmable-logic-controller-plc-market&quot;&gt;$13 billion market&lt;/a&gt;. And yet, most of us have never heard of them.&lt;/p&gt;
&lt;p&gt;This article breaks down what PLCs actually are, traces their evolution from Morley&#39;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.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-plc-(programmable-logic-controller)-%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#what-is-a-plc-(programmable-logic-controller)-%3F&quot;&gt;What is a PLC (Programmable Logic Controller) ?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &amp;quot;scan cycle,&amp;quot; typically thousands of times per second. Read inputs. Run logic. Update outputs. Repeat. Forever.&lt;/p&gt;
&lt;p&gt;What sets PLCs apart isn&#39;t computing power—your phone vastly outperforms them. It&#39;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&#39;t a nice-to-have. It&#39;s survival.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;This design has barely changed since Morley&#39;s 1968 specifications, and there&#39;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&#39;t embrace Silicon Valley&#39;s &amp;quot;move fast and break things.&amp;quot; The motto here is simpler: never break.&lt;/p&gt;
&lt;h2 id=&quot;history-of-plcs%3A-from-relay-rooms-to-smart-controllers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#history-of-plcs%3A-from-relay-rooms-to-smart-controllers&quot;&gt;History of PLCs: From Relay Rooms to Smart Controllers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Pre-PLC industrial relay control cabinet used in factories before programmable logic controllers replaced hard-wired relay logic
&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pre-plc-relay-cabinet.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Pre-PLC industrial relay control cabinet used in factories before programmable logic controllers replaced hard-wired relay logic&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;On New Year&#39;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 &amp;quot;Programmable Controller&amp;quot;—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&#39;d later regret: he wanted it to operate slowly.&lt;/p&gt;
&lt;p&gt;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&#39;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&#39;s 84th project.&lt;/p&gt;
&lt;p&gt;To commercialize the design, they needed investors. The team formed a new company in October 1968, calling it &lt;strong&gt;Modicon&lt;/strong&gt;—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.&lt;/p&gt;
&lt;p&gt;General Motors heard about Modicon&#39;s work and placed a million-dollar order. In November 1969, GM&#39;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&#39;s founding, the PLC had gone from hungover memo to production deployment at the world&#39;s largest automaker.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;PLC Pioneers Richard Morley, Tom Bossevain, George Schwenk and Jonas Landau
&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/First-modicon-084.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;PLC Pioneers Richard Morley, Tom Bossevain, George Schwenk and Jonas Landau&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Morley always called himself the &amp;quot;Father&amp;quot; of the PLC rather than its &amp;quot;Inventor&amp;quot;—he knew others were working on similar solutions and believed the technology &amp;quot;invented itself out of necessity.&amp;quot; Bedford Associates eventually dissolved to avoid tax complications after Modicon&#39;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.&lt;/p&gt;
&lt;h2 id=&quot;how-a-plc-works%3A-scan-cycle%2C-inputs%2C-and-outputs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#how-a-plc-works%3A-scan-cycle%2C-inputs%2C-and-outputs&quot;&gt;How a PLC Works: Scan Cycle, Inputs, and Outputs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open a PLC cabinet on a factory floor and you&#39;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&#39;s been running since installation—sometimes for decades.&lt;/p&gt;
&lt;p&gt;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&#39;s not elegant. It&#39;s not exciting. But it&#39;s exactly what keeps production lines moving and chemical reactors stable.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-actually-inside-a-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#what&#39;s-actually-inside-a-plc&quot;&gt;What&#39;s Actually Inside a PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The CPU&lt;/strong&gt; runs your control program. Modern units use industrial microprocessors—nothing exotic, just chips designed for temperature extremes and long-term reliability. They&#39;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input modules&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output modules&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The power supply&lt;/strong&gt; 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&#39;s rated for abuse because industrial power is chaos.&lt;/p&gt;
&lt;h3 id=&quot;the-scan-cycle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#the-scan-cycle&quot;&gt;The Scan Cycle&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every PLC runs the same four-step loop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Input scan&lt;/strong&gt;: Copy all sensor states into memory. This creates a snapshot—every input frozen at one moment in time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Program execution&lt;/strong&gt;: Run the control logic from start to finish using that snapshot. If temperature &amp;gt; 250°F, open cooling valve. If part detected AND quality check passed, advance conveyor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Output update&lt;/strong&gt;: 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.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Housekeeping&lt;/strong&gt;: Handle communications, diagnostics, error checking. Then start over immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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&#39;s been doing this in some facilities since the 1980s.&lt;/p&gt;
&lt;p&gt;This approach eliminates entire classes of software bugs. Inputs can&#39;t change mid-program. Outputs can&#39;t update while logic is executing. Race conditions don&#39;t exist. The program runs in strict sequential order, identically, every scan.&lt;/p&gt;
&lt;h3 id=&quot;programming-languages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#programming-languages&quot;&gt;Programming Languages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PLCs don&#39;t use Python or C++. They use &lt;a href=&quot;https://en.wikipedia.org/wiki/IEC_61131-3&quot;&gt;IEC 61131-3&lt;/a&gt; languages designed for industrial electricians and control engineers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ladder Logic&lt;/strong&gt; 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&#39;s clunky for complex math but perfect for discrete control—if sensor A triggers and valve B is closed, start pump C.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function Block Diagrams&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structured Text&lt;/strong&gt; handles complex calculations and algorithms. It looks like Pascal. Modern applications increasingly need it—ladder logic becomes unmanageable for sophisticated control strategies.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;why-plcs-haven&#39;t-changed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#why-plcs-haven&#39;t-changed&quot;&gt;Why PLCs Haven&#39;t Changed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;Because reliability beats performance in industrial automation. A PLC controlling a gas turbine or pharmaceutical batch doesn&#39;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.&lt;/p&gt;
&lt;p&gt;Consumer computing optimizes for speed and features. Industrial computing optimizes for never failing. Ever. The scan cycle, the isolated I/O, the deterministic execution—these aren&#39;t limitations. They&#39;re the exact solution the problem requires.&lt;/p&gt;
&lt;p&gt;That&#39;s why Morley&#39;s 1968 architecture still dominates. Not because the industry is conservative or backwards. Because he solved the problem correctly the first time.&lt;/p&gt;
&lt;h2 id=&quot;types-of-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#types-of-plcs&quot;&gt;Types of PLCs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;compact-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#compact-plcs&quot;&gt;Compact PLCs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Compact PLCs integrate the CPU, I/O, and power supply into a single fixed unit. They typically handle 10–100 I/O 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/O modules, but scalability is constrained. Once that limit is reached, upgrading to a modular PLC is usually required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt; Siemens S7-1200, Rockwell Micro800, Schneider Modicon M221&lt;/p&gt;
&lt;h3 id=&quot;modular-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#modular-plcs&quot;&gt;Modular PLCs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modular PLCs separate the CPU from the I/O modules, which are installed on expandable racks. Need hundreds of I/O 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt; Siemens S7-1500, Rockwell ControlLogix, Schneider Modicon M580&lt;/p&gt;
&lt;h3 id=&quot;safety-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#safety-plcs&quot;&gt;Safety PLCs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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 / 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt; Pilz PNOZmulti, Siemens F-series, Rockwell GuardLogix&lt;/p&gt;
&lt;h3 id=&quot;micro-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#micro-plcs&quot;&gt;Micro PLCs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Micro PLCs handle very small automation tasks, typically 8–20 I/O 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt; Unitronics, AutomationDirect CLICK, IDEC SmartRelay&lt;/p&gt;
&lt;h3 id=&quot;choosing-the-right-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#choosing-the-right-plc&quot;&gt;Choosing the Right PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Selecting a PLC comes down to I/O count, system complexity, safety requirements, and future expansion. Simple machines with fewer than 20 I/O points are well served by micro or compact PLCs. Production lines with hundreds of I/O 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.&lt;/p&gt;
&lt;h2 id=&quot;plc%2C-hmi%2C-and-scada%3A-how-they-work-together&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#plc%2C-hmi%2C-and-scada%3A-how-they-work-together&quot;&gt;PLC, HMI, and SCADA: How They Work Together&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A PLC executes control logic in milliseconds, but it doesn&#39;t have a screen. It can&#39;t show operators what&#39;s happening. It can&#39;t log historical data or send alerts. That&#39;s where HMIs and SCADA systems come in.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;This hierarchy only works if these systems can actually talk to each other. That&#39;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&#39;ll tackle next.&lt;/p&gt;
&lt;h2 id=&quot;where-plcs-actually-run%3A-real-world-applications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#where-plcs-actually-run%3A-real-world-applications&quot;&gt;Where PLCs Actually Run: Real-World Applications&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PLCs control processes where reliability isn&#39;t negotiable. They&#39;re not exciting. They&#39;re not visible. But they&#39;re running constantly in factories, utilities, and infrastructure—often for decades without replacement.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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&#39;ve executed millions of times.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;the-interoperability-problem%3A-when-plcs-won&#39;t-talk&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#the-interoperability-problem%3A-when-plcs-won&#39;t-talk&quot;&gt;The Interoperability Problem: When PLCs Won&#39;t Talk&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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&#39;s unintended legacy.&lt;/p&gt;
&lt;p&gt;Every major PLC manufacturer built their own proprietary ecosystem. Siemens controllers speak different protocols than Rockwell. Schneider systems don&#39;t natively understand Mitsubishi. Walk into any facility and you&#39;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The cost isn&#39;t just technical debt. It&#39;s strategic paralysis. Companies stick with a single vendor not because they offer the best solution, but because switching is too painful.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-breaking-the-integration-barrier&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/#flowfuse%3A-breaking-the-integration-barrier&quot;&gt;FlowFuse: Breaking the Integration Barrier&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;, built on &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt;, solves the protocol chaos that vendor lock-in created. Node-RED emerged from IBM in 2013, created by &lt;a href=&quot;https://www.linkedin.com/in/nickoleary/&quot;&gt;Nick O&#39;Leary&lt;/a&gt; (now CTO of FlowFuse) and &lt;a href=&quot;https://github.com/dceejay&quot;&gt;Dave Conway-Jones&lt;/a&gt; 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/IP, S7comm, OPC UA, and more. It became the universal translator for industrial systems.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse platform for industrial data integration connecting PLCs, Node-RED, and enterprise systems
&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-platform.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse platform for industrial data integration connecting PLCs, Node-RED, and enterprise systems&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;FlowFuse doesn&#39;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.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://flowfuse.com/customer-stories/manufacturing-digital-transformation/&quot;&gt;large US manufacturing company&lt;/a&gt; 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&#39;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.&lt;/p&gt;
&lt;p&gt;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.
Want to see how FlowFuse handles PLC integration in your environment? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; with our team—we&#39;ll connect to your mixed-vendor systems and show you what&#39;s possible in under an hour.&lt;/p&gt;
&lt;p&gt;Dick Morley&#39;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.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/node-red-timer/</id>
        <title>Node-RED Timer Tutorial: Create Stopwatch and Countdown Timers</title>
        <summary>Implement stopwatch and countdown timers for industrial automation and process control applications</summary>
        <updated>2025-12-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/node-red-timer/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Timers are everywhere in industrial automation. You need them to track how long a machine has been running, measure downtime, schedule maintenance, or coordinate processes that happen in sequence.&lt;/p&gt;
&lt;p&gt;Through my work as a technical writer covering IIoT, building industrial applications, and being part of a company where our customers deploy real-world automation systems, I&#39;ve observed that &lt;strong&gt;timers&lt;/strong&gt; are ubiquitous in production environments. Whether it&#39;s a production floor display showing machine runtime, a maintenance terminal counting down to the next service window, or an operator interface tracking downtime by reason code—timers are foundational to industrial visibility. Here&#39;s an example of a performance operator terminal with timer functionality:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Performance Operator Terminal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/performance-operator-terminal.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Performance operator terminal displaying real-time production metrics with timer functionality&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you want to explore this interface yourself, you can &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/performance-operator-terminal/&quot;&gt;deploy this blueprint&lt;/a&gt; to your &lt;strong&gt;FlowFuse&lt;/strong&gt; instance and start experimenting immediately.&lt;/p&gt;
&lt;p&gt;In this article, we&#39;ll build two types of timers in &lt;a href=&quot;https://flowfuse.com/&quot;&gt;Node-RED&lt;/a&gt;: &lt;strong&gt;stopwatches&lt;/strong&gt; that measure elapsed time and countdowns that trigger actions after a set duration. Both are straightforward to implement and essential for most automation projects.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before following this tutorial, you should have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A running &lt;strong&gt;Node-RED instance&lt;/strong&gt;. For professional development and production deployments, &lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;&lt;/strong&gt; is the recommended platform. If you don’t have an account, &lt;a href=&quot;http://app.flowfuse.com/&quot;&gt;start your free trial&lt;/a&gt; today.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;FlowFuse provides enterprise-grade Node-RED hosting with managed infrastructure, built-in &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;DevOps tools&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-3%3A-set-up-mqtt-with-flowfuse&quot;&gt;MQTT broker&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/&quot;&gt;database&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/&quot;&gt;team collaboration&lt;/a&gt; with &lt;a href=&quot;https://www.youtube.com/watch?v=mb1s1YQIpZY&quot;&gt;granular access control&lt;/a&gt;, and seamless scaling capabilities. Whether you need cloud-hosted instances managed by FlowFuse or remote instances running on your edge devices, the platform provides unified management for both. FlowFuse also includes AI-powered features that accelerate flow development and streamline automation projects. From prototyping to mission-critical production deployments, FlowFuse handles the infrastructure complexity so you can focus on building flows.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s all you need to get started.&lt;/p&gt;
&lt;h1 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We&#39;ll use two Node-RED community nodes for this tutorial: &lt;strong&gt;node-red-contrib-hourglass&lt;/strong&gt; for stopwatch timers and node-red-contrib-countdown for &lt;strong&gt;countdown timers&lt;/strong&gt;. Both are simple to configure and work reliably in production environments.&lt;/p&gt;
&lt;p&gt;Let&#39;s start with installing and building a stopwatch.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-hourglass-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#installing-the-hourglass-node&quot;&gt;Installing the Hourglass Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, install the &lt;strong&gt;hourglass node&lt;/strong&gt; in your Node-RED instance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;hamburger menu&lt;/strong&gt; (top right) and select &amp;quot;Manage palette&amp;quot;&lt;/li&gt;
&lt;li&gt;Go to the &amp;quot;Install&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-hourglass&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;&amp;quot;Install&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;strong&gt;hourglass node&lt;/strong&gt; will appear in your palette under the function category.&lt;/p&gt;
&lt;h2 id=&quot;understanding-hourglass-commands&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#understanding-hourglass-commands&quot;&gt;Understanding Hourglass Commands&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hourglass node responds to control commands sent via &lt;code&gt;msg.command&lt;/code&gt;. The available commands are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;start&lt;/strong&gt; - Begins timing operation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;stop&lt;/strong&gt; - Stops the timer and outputs elapsed time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pause&lt;/strong&gt; - Pauses timing without resetting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;reset&lt;/strong&gt; - Clears timer state and stops operation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;status&lt;/strong&gt; - Outputs current timer state without stopping&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These commands control timer behavior.&lt;/p&gt;
&lt;h3 id=&quot;implementing-a-stopwatch-timer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#implementing-a-stopwatch-timer&quot;&gt;Implementing a Stopwatch Timer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Build a basic &lt;strong&gt;stopwatch flow&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag four inject nodes onto the canvas&lt;/li&gt;
&lt;li&gt;Add four &lt;strong&gt;change nodes&lt;/strong&gt;, one after each inject node, and connect them&lt;/li&gt;
&lt;li&gt;Configure the change nodes to set &lt;code&gt;msg.command&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;First &lt;strong&gt;change node&lt;/strong&gt;: set to &lt;code&gt;&amp;quot;start&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Second change node: set to &lt;code&gt;&amp;quot;status&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Third &lt;strong&gt;change node&lt;/strong&gt;: set to &lt;code&gt;&amp;quot;stop&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fourth change node: set to &lt;code&gt;&amp;quot;reset&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;hourglass node&lt;/strong&gt; onto the canvas&lt;/li&gt;
&lt;li&gt;Connect all four change nodes to the &lt;strong&gt;hourglass node&lt;/strong&gt; input&lt;/li&gt;
&lt;li&gt;Add a debug node and connect it to the hourglass node output&lt;/li&gt;
&lt;li&gt;Deploy the flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When you trigger the first inject node, the &lt;strong&gt;stopwatch starts&lt;/strong&gt;. The second inject node checks current elapsed time without stopping the timer—you can configure this inject node to repeat at intervals for continuous time monitoring. The third inject node stops the &lt;strong&gt;stopwatch&lt;/strong&gt; and outputs the total elapsed time. The fourth inject node resets the stopwatch back to zero.&lt;/p&gt;
&lt;p&gt;The node outputs a message containing timing information:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Hourglass node output message showing elapsed time in multiple formats&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/hourglass-output.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Hourglass node output message showing elapsed time in multiple formats&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;elapsed&lt;/code&gt; object provides multiple formats: a human-readable string, total milliseconds, and broken-down time components. This flexibility supports different display requirements and calculation needs.&lt;/p&gt;
&lt;p&gt;This basic example demonstrates the pattern. In production applications, replace the inject nodes with actual process triggers—&lt;strong&gt;machine status signals&lt;/strong&gt; from PLCs or MQTT messages from sensors. The &lt;strong&gt;hourglass node output&lt;/strong&gt; then connects to databases for logging, dashboards for visualization, or notification systems for alerts when thresholds are exceeded.&lt;/p&gt;
&lt;p&gt;Below is the complete flow.&lt;/p&gt;
&lt;div id=&quot;nr-flow-253&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow253 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;81365fac1ccf6299&#92;&quot;,&#92;&quot;65cf5a523eaee926&#92;&quot;,&#92;&quot;560a9271f2b46687&#92;&quot;,&#92;&quot;4c5449af7a4dd6ef&#92;&quot;,&#92;&quot;e8400461cd50b356&#92;&quot;,&#92;&quot;55a008aab6204565&#92;&quot;,&#92;&quot;18630deedc38af9f&#92;&quot;,&#92;&quot;9ef4a745bd0194cf&#92;&quot;,&#92;&quot;cf84add540c079ce&#92;&quot;,&#92;&quot;35ab3bbb1674b4f6&#92;&quot;],&#92;&quot;x&#92;&quot;:194,&#92;&quot;y&#92;&quot;:2231,&#92;&quot;w&#92;&quot;:892,&#92;&quot;h&#92;&quot;:230},{&#92;&quot;id&#92;&quot;:&#92;&quot;81365fac1ccf6299&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;hourglass&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;humanizeLocale&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:2340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9ef4a745bd0194cf&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;65cf5a523eaee926&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Auto Start&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;date&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:2272,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;560a9271f2b46687&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;560a9271f2b46687&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Start&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;start&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:2272,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;81365fac1ccf6299&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4c5449af7a4dd6ef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Status&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;status&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:2320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;81365fac1ccf6299&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e8400461cd50b356&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Stop&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;stop&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:2368,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;81365fac1ccf6299&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;55a008aab6204565&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read every 1 seconds&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:2320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4c5449af7a4dd6ef&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18630deedc38af9f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Manual Stop&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;date&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:2369,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e8400461cd50b356&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9ef4a745bd0194cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:2340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cf84add540c079ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Reset&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;reset&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:2420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;81365fac1ccf6299&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;35ab3bbb1674b4f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a8e05e4b1a8a8e5e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Manual Reset&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:2420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cf84add540c079ce&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5191dd25898c631c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-hourglass&#92;&quot;:&#92;&quot;1.5.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow253.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-253&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;implementing-a-countdown-timer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#implementing-a-countdown-timer&quot;&gt;Implementing a Countdown Timer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Countdown timers trigger actions after a specified duration. Common applications include scheduled maintenance windows, batch process timeouts, and timed equipment shutdowns.&lt;/p&gt;
&lt;p&gt;To implement a countdown, we will use &lt;code&gt;node-red-contrib-countdown&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;installing-the-countdown-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#installing-the-countdown-node&quot;&gt;Installing the Countdown Node&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Install the &lt;strong&gt;countdown node&lt;/strong&gt; in your Node-RED instance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the hamburger menu (top right) and select &lt;strong&gt;&amp;quot;Manage palette&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &amp;quot;Install&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-countdown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;&amp;quot;Install&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The countdown node will appear in your palette.&lt;/p&gt;
&lt;h3 id=&quot;building-a-countdown-timer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#building-a-countdown-timer&quot;&gt;Building a Countdown Timer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a &lt;strong&gt;countdown timer flow&lt;/strong&gt; in Node-RED:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a Change node and configure it to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the countdown duration in &lt;strong&gt;seconds&lt;/strong&gt; (for example, &lt;code&gt;50&lt;/code&gt; for 50 seconds).&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.topic&lt;/code&gt; to &lt;code&gt;&amp;quot;control&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can configure the countdown duration either in the &lt;strong&gt;Change&lt;/strong&gt; node or directly in the Inject node, as long as &lt;code&gt;msg.payload&lt;/code&gt; is in milliseconds and &lt;code&gt;msg.topic&lt;/code&gt; is &lt;code&gt;&amp;quot;control&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Countdown&lt;/strong&gt; node onto the canvas and configure it with the following settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Timer On payload&lt;/strong&gt;: The message payload sent when the countdown starts (for example, &lt;code&gt;true&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timer Off payload&lt;/strong&gt;: The message payload sent when the countdown completes (for example, &lt;code&gt;false&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restart countdown if message is received while running&lt;/strong&gt;: Enable this to restart the countdown if a new control message is received.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send output message on Reset&lt;/strong&gt;: Enable this to send a message when the countdown is reset.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set time to new duration if control message is received while running&lt;/strong&gt;: Enable this to update the countdown duration while it is running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start countdown if control message is received while not running&lt;/strong&gt;: Enable this to start the countdown using a control message, enable it for this example to allow starting countdown when control message recived&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Change node to the &lt;strong&gt;Countdown&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node and connect it to the Countdown node output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to activate the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When you trigger the Inject node, the &lt;strong&gt;countdown starts&lt;/strong&gt;. The Countdown node outputs messages at regular intervals, and the &lt;strong&gt;second output&lt;/strong&gt; shows the remaining time.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Countdown node output showing remaining time updates&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/countdown.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Countdown node output showing remaining time updates&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;From the first output, it will send the message you configured at the start of the count and at the end of the countdown.&lt;/p&gt;
&lt;p&gt;Below is the flow implementation that you can use as a starting point.&lt;/p&gt;
&lt;div id=&quot;nr-flow-254&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow254 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;0a7fdceb7b844c76&#92;&quot;,&#92;&quot;b1d36b608bafb531&#92;&quot;,&#92;&quot;e7e0894b2832e93e&#92;&quot;,&#92;&quot;52d0abe15e3533c8&#92;&quot;,&#92;&quot;c48dcaec998440aa&#92;&quot;],&#92;&quot;x&#92;&quot;:134,&#92;&quot;y&#92;&quot;:3419,&#92;&quot;w&#92;&quot;:692,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;0a7fdceb7b844c76&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;countdown&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadTimerStart&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;payloadTimerStartType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;payloadTimerStop&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;payloadTimerStopType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;timer&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;resetWhileRunning&#92;&quot;:false,&#92;&quot;outputOnReset&#92;&quot;:false,&#92;&quot;setTimeToNewWhileRunning&#92;&quot;:false,&#92;&quot;startCountdownOnControlMessage&#92;&quot;:true,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:3480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e7e0894b2832e93e&#92;&quot;],[&#92;&quot;52d0abe15e3533c8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b1d36b608bafb531&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Start&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:230,&#92;&quot;y&#92;&quot;:3480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c48dcaec998440aa&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7e0894b2832e93e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:3460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;52d0abe15e3533c8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Countdown&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:3500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c48dcaec998440aa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b446dfa04d79d359&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;13e3937b0555d34d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set Countdown&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;control&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:3480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0a7fdceb7b844c76&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;66be08ead79304bf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-countdown&#92;&quot;:&#92;&quot;1.3.2&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow254.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-254&#39;) })&lt;/script&gt;
&lt;p&gt;For this demonstration, we used an inject node to manually trigger the countdown. In production environments, you would replace this with actual process triggers—&lt;strong&gt;equipment status signals&lt;/strong&gt; from &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/&quot;&gt;PLCs&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; messages from sensors, or completion signals from upstream operations. For example, you might start a &lt;strong&gt;maintenance window countdown&lt;/strong&gt; when equipment reaches a scheduled service interval, or initiate a cleanup cycle timer when a batch process completes.&lt;/p&gt;
&lt;p&gt;While these examples cover the essential timer operations, both nodes offer additional configuration options. For comprehensive documentation, visit the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-hourglass&quot;&gt;node-red-contrib-hourglass&lt;/a&gt; and &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-countdown&quot;&gt;node-red-contrib-countdown&lt;/a&gt; pages on the &lt;strong&gt;Node-RED flows library&lt;/strong&gt;.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-timer/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;That&#39;s it, you now have working &lt;strong&gt;stopwatch&lt;/strong&gt; and &lt;strong&gt;countdown timers&lt;/strong&gt; in Node-RED. The hourglass node tracks elapsed time, and the countdown node triggers actions after a set duration.&lt;/p&gt;
&lt;p&gt;These implementations are ready for production use. Start with these basic patterns, test them in your environment, and expand as needed. Connect them to your &lt;strong&gt;PLCs&lt;/strong&gt;, add dashboard displays, or integrate with your existing automation workflows.&lt;/p&gt;
&lt;p&gt;Both nodes are actively maintained and used in real industrial systems, so you&#39;re building on proven foundations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/</id>
        <title>Five Whys Root Cause Analysis: Definition, Steps &amp; Examples (2026)</title>
        <summary>A proven root cause analysis technique for solving recurring problems in manufacturing, operations, and continuous improvement.</summary>
        <updated>2025-12-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The Five Whys is a root cause analysis technique where you ask &amp;quot;why&amp;quot; repeatedly—typically five times—until you identify the underlying systemic cause instead of just symptoms.&lt;/p&gt;
&lt;p&gt;Your equipment fails on Tuesday. The maintenance team fixes it. It fails again on Friday. They fix it again. Three weeks later, same failure. This cycle continues because everyone treats the symptom—the broken part—instead of asking why it broke.&lt;/p&gt;
&lt;p&gt;The Five Whys breaks this pattern. Developed by Sakichi Toyoda at Toyota in the 1930s, it&#39;s become the standard root cause analysis method across manufacturing, healthcare, software development, and anywhere recurring problems drain productivity. The technique works through systematic questioning that strips away symptoms to expose fixable failures in your systems—the process gaps, training deficiencies, and procedural weaknesses that allow problems to persist. When applied correctly, it takes under an hour and prevents problems from returning.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-five-whys-root-cause-analysis-method%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#what-is-the-five-whys-root-cause-analysis-method%3F&quot;&gt;What Is the Five Whys Root Cause Analysis Method?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Five Whys root cause analysis is a questioning technique where you ask &amp;quot;why&amp;quot; a problem occurred, then ask &amp;quot;why&amp;quot; that condition existed, then keep asking until you hit something you can actually fix at a systemic level. It was developed by Sakichi Toyoda in the 1930s and became a core tool in the Toyota Production System. Today it&#39;s used across manufacturing, healthcare, software development, and anywhere else people need to solve recurring problems.&lt;/p&gt;
&lt;p&gt;The technique is deceptively simple. You start with a specific problem. You ask why it happened. You take that answer and ask why again. You keep going until asking &amp;quot;why&amp;quot; one more time would just be splitting hairs or rehashing what you already know. Usually that takes about five iterations—the number comes from the observation that five whys is typically sufficient to reveal the root cause—but I&#39;ve seen effective analyses that stopped at three and others that went to eight.&lt;/p&gt;
&lt;p&gt;Watch this video if you prefer video format:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;-_nN_YTDsuk&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-the-five-whys-works-when-other-methods-don&#39;t&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#why-the-five-whys-works-when-other-methods-don&#39;t&quot;&gt;Why the Five Whys Works When Other Methods Don&#39;t&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Organizations often spend weeks on elaborate root cause analyses using &lt;a href=&quot;https://en.wikipedia.org/wiki/Fault_tree_analysis&quot;&gt;fault trees&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Ishikawa_diagram&quot;&gt;fishbone diagrams&lt;/a&gt;, and &lt;a href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/&quot;&gt;statistical process control charts&lt;/a&gt;, only to implement solutions that don&#39;t stick. The Five Whys succeeds where these methods often fail for three reasons.&lt;/p&gt;
&lt;p&gt;First, it&#39;s fast. You can complete a thorough analysis in under an hour. That speed matters because problems are freshest when they just happened. Witnesses remember details. Physical evidence hasn&#39;t been cleaned up or moved. The sense of urgency is still there. Wait two weeks to schedule your analysis meeting, and you&#39;re working from memory and assumptions.&lt;/p&gt;
&lt;p&gt;Second, it&#39;s accessible. The machine operator who saw the problem doesn&#39;t need training in statistical methods or failure mode analysis. They just need to answer questions honestly about what they observed. This democratization of problem-solving means you&#39;re not waiting for specialists to free up their calendars. The people closest to the work can solve problems themselves.&lt;/p&gt;
&lt;p&gt;Third, it forces you to follow a single causal chain all the way down. Other methods encourage you to map out every possible contributing factor simultaneously. That comprehensiveness sounds good in theory, but in practice it often leads to analysis paralysis. You&#39;ve identified seventeen potential causes, and now you&#39;re trying to fix all of them at once. The Five Whys makes you pick the most likely path and follow it to the end. You can always come back and explore alternative explanations if your first solution doesn&#39;t work.&lt;/p&gt;
&lt;h2 id=&quot;the-five-whys-checklist%3A-what-you-need-before-you-start&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#the-five-whys-checklist%3A-what-you-need-before-you-start&quot;&gt;The Five Whys Checklist: What You Need Before You Start&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most failed Five Whys sessions fail before they even begin because people skip the setup. You need four things in place before you ask the first question.&lt;/p&gt;
&lt;p&gt;Before you ask the first question, you need four things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A specific problem statement.&lt;/strong&gt; &amp;quot;Quality issues in Department B&amp;quot; won&#39;t work. &amp;quot;Thirty-seven units failed final inspection on December 18th due to incomplete welds&amp;quot; will. Specificity disciplines your thinking and keeps the analysis focused.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The right people.&lt;/strong&gt; That means at least one person who directly observed or experienced the problem, someone who understands the process well enough to spot abnormal conditions, and a facilitator who can keep the questions moving forward. Three to five people is ideal. More than that and you&#39;ll spend more time managing the discussion than conducting the analysis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Location at the gemba.&lt;/strong&gt; Conduct the analysis close to where the problem occurred. This principle, which Toyota calls &lt;a href=&quot;https://en.wikipedia.org/wiki/Gemba&quot;&gt;gemba&lt;/a&gt;, matters more than most people realize. Conference rooms encourage abstract thinking. The shop floor, the customer service desk, or the server room keeps everyone grounded in physical reality. You can point at things. You can test hypotheses on the spot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commitment to honest answers.&lt;/strong&gt; If the real reason your new hires keep making mistakes is that your training program is inadequate, you need people willing to say that out loud. If your preventive maintenance schedule was designed fifteen years ago and never updated, someone needs to acknowledge it. The Five Whys only works if people tell the truth about what they see.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-complete-a-five-whys-root-cause-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#how-to-complete-a-five-whys-root-cause-analysis&quot;&gt;How to Complete a Five Whys Root Cause Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The mechanics of the method are straightforward, but execution requires more care than most people expect.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Five Whys funnel diagram from problem to root cause&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/5-Why-Funnel.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Five Whys funnel diagram from problem to root cause&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Start by stating the problem as precisely as you can. Write it down where everyone can see it. If you&#39;re working through this at the gemba, write it on a whiteboard or a large sheet of paper. If you&#39;re remote, put it in a shared document. The problem statement anchors everything that follows, so take the time to get it right. Include what happened, when it happened, where it happened, and how you know it happened. Measurements matter here. &amp;quot;Production was slow&amp;quot; is too vague. &amp;quot;Line 3 produced 847 units against a target of 1,000 units during the first shift on December 20th&amp;quot; gives you something concrete to investigate.&lt;/p&gt;
&lt;p&gt;Ask your first why: Why did this specific problem occur? The answer should be factual, not speculative. &amp;quot;I think maybe the bearings were worn&amp;quot; isn&#39;t good enough. &amp;quot;The motor seized, and when we disassembled it, we found metal shavings in the bearing housing&amp;quot; is what you&#39;re after. If you don&#39;t know the answer with certainty, stop and gather evidence before continuing.&lt;/p&gt;
&lt;p&gt;Take that answer and ask why again. Why did the motor bearings fail? Because the lubrication system wasn&#39;t delivering oil to that bearing. How do you know? Because we checked the oil flow and found the feed line was clogged. This is where many analyses go wrong. People start speculating instead of observing. They say things like &amp;quot;probably the operator forgot to check it&amp;quot; when what they actually know is that the line was clogged. Stick to what you can verify.&lt;/p&gt;
&lt;p&gt;Continue this pattern. Each answer becomes the subject of the next question. Why was the feed line clogged? Because particulate from the oil reservoir got into the line. Why was there particulate in the reservoir? Because we&#39;re not filtering the oil when we top off the reservoir. Why aren&#39;t we filtering it? Because the maintenance procedure doesn&#39;t specify using a filter when adding oil.&lt;/p&gt;
&lt;p&gt;Stop when you&#39;ve identified a process failure or systemic gap. In this case, the inadequate maintenance procedure is your root cause. It&#39;s something you can fix with a clear corrective action: revise the maintenance procedure to require filtered oil and provide the appropriate filtering equipment. That&#39;s different from &amp;quot;operator error&amp;quot; or &amp;quot;equipment failure,&amp;quot; which are symptoms, not causes.&lt;/p&gt;
&lt;p&gt;Notice that this example took exactly five questions, but that&#39;s coincidental. Effective analyses sometimes reach the root cause in three questions and other times need eight. The number doesn&#39;t matter. What matters is reaching the point where you&#39;ve identified something you can actually fix.&lt;/p&gt;
&lt;h2 id=&quot;when-and-where-should-you-use-the-five-whys%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#when-and-where-should-you-use-the-five-whys%3F&quot;&gt;When and Where Should You Use the Five Whys?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Five Whys is particularly effective for problems with a dominant causal chain. If your problem has one primary cause with some contributing factors, this method will find it quickly. It works well for equipment failures, quality defects, process bottlenecks, safety incidents, and customer complaints where you&#39;re trying to understand what broke down in your systems.&lt;/p&gt;
&lt;p&gt;It&#39;s less effective for complex problems with multiple simultaneous causes that interact with each other. If you&#39;re investigating a major product recall with contributing factors spanning design, materials, manufacturing, and distribution, the Five Whys will feel inadequate. You&#39;re better off with something like fishbone analysis or fault tree analysis that lets you map multiple causal pathways simultaneously.&lt;/p&gt;
&lt;p&gt;The method also struggles with problems that have deep organizational or cultural roots. If your real issue is that nobody wants to report problems because they fear retaliation, asking &amp;quot;why&amp;quot; five times might surface that fact, but fixing it requires organizational change management that&#39;s well beyond what a questioning technique can address. The Five Whys can identify the issue, but you&#39;ll need other tools to solve it.&lt;/p&gt;
&lt;p&gt;The method works well for equipment failures and maintenance issues, quality problems that recur despite corrections, process bottlenecks that resist obvious solutions, safety incidents requiring rapid investigation, and customer complaints where you need to fix internal processes. It struggles with problems that have multiple independent causes, new product development scenarios where you&#39;re trying to prevent future failures, strategic planning issues, and situations where participants don&#39;t have sufficient knowledge to answer accurately.&lt;/p&gt;
&lt;h2 id=&quot;the-toyota-five-whys%3A-where-this-method-came-from&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#the-toyota-five-whys%3A-where-this-method-came-from&quot;&gt;The Toyota Five Whys: Where This Method Came From&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Sakichi_Toyoda&quot;&gt;Sakichi Toyoda&lt;/a&gt; developed the Five Whys in the 1930s as part of the manufacturing methodology that would eventually become the &lt;a href=&quot;https://en.wikipedia.org/wiki/Toyota_Production_System&quot;&gt;Toyota Production System&lt;/a&gt;. Toyoda, who founded what would become Toyota Industries, was obsessed with understanding why things failed. His approach was radical for its time: instead of accepting problems as inevitable, he insisted they were symptoms of deeper issues that could be identified and eliminated.&lt;/p&gt;
&lt;p&gt;His son &lt;a href=&quot;https://en.wikipedia.org/wiki/Kiichiro_Toyoda&quot;&gt;Kiichiro Toyoda&lt;/a&gt; and engineer &lt;a href=&quot;https://en.wikipedia.org/wiki/Taiichi_Ohno&quot;&gt;Taiichi Ohno&lt;/a&gt; refined the method as they developed Toyota&#39;s production system in the decades after World War II. They formalized the practice of going to the gemba to observe problems firsthand and asking why until you hit something systemic rather than symptomatic.&lt;/p&gt;
&lt;p&gt;Toyota&#39;s success with this approach attracted attention in the 1970s and 1980s when Western manufacturers were trying to understand why Japanese companies were outcompeting them. The Five Whys spread beyond automotive manufacturing into other industries, though often without the cultural foundation that made it effective at Toyota. Many companies adopted the technique as a standalone tool without understanding that it only works in an environment where people feel safe identifying systemic problems and where management is committed to fixing them.&lt;/p&gt;
&lt;p&gt;That context matters when you&#39;re implementing the Five Whys in your organization. The technique itself is simple, but it won&#39;t survive in a culture that shoots the messenger or treats problem identification as complaining rather than continuous improvement.&lt;/p&gt;
&lt;h2 id=&quot;best-practices-from-experienced-root-cause-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#best-practices-from-experienced-root-cause-analysis&quot;&gt;Best Practices From Experienced Root Cause Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Focus on processes and systems, not people. When your analysis points to an individual who made a mistake, don&#39;t stop there. Ask why that mistake was possible. Why didn&#39;t training cover this situation? Why didn&#39;t the procedure include a verification step? Why wasn&#39;t there a physical or administrative control that would have caught the error? Robust processes assume people will make mistakes and build in safeguards. If your process allows one person&#39;s mistake to cause a significant problem, your process is inadequate.&lt;/p&gt;
&lt;p&gt;Verify every answer before moving to the next question. The Five Whys fails when it becomes an exercise in brainstorming rather than investigation. Each answer should be based on evidence you can point to: physical observations, data from sensors or logs, documents, measurements, or direct testimony from witnesses. If your team is guessing, stop and gather facts.&lt;/p&gt;
&lt;p&gt;Stay on one causal chain at a time. Real problems often have multiple contributing causes, and your team will want to explore all of them simultaneously. Resist this. Follow the most likely path all the way to the end first. If the corrective actions you implement don&#39;t solve the problem, you can come back and explore alternative paths. Trying to investigate everything at once creates confusion and dilutes your focus.&lt;/p&gt;
&lt;p&gt;Keep your questions neutral. &amp;quot;Why did the operator forget to check the pressure?&amp;quot; assumes forgetfulness and points toward blame. &amp;quot;Why wasn&#39;t the pressure checked?&amp;quot; opens up multiple possibilities including procedural gaps, time pressure, distraction, inadequate training, or unclear responsibility. How you phrase the question shapes what answers you&#39;ll get.&lt;/p&gt;
&lt;p&gt;Know when to stop. You&#39;ve found your root cause when the answer identifies something you can fix through a procedural change, a training modification, a design improvement, or another corrective action that addresses the systemic level. If you keep asking why beyond that point, you&#39;ll end up with philosophical answers about organizational culture or budget constraints that aren&#39;t actionable in the context of this specific problem.&lt;/p&gt;
&lt;h2 id=&quot;common-mistakes-that-undermine-five-whys-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#common-mistakes-that-undermine-five-whys-analysis&quot;&gt;Common Mistakes That Undermine Five Whys Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most frequent mistake is stopping at symptoms. A part fails, and the team replaces it, logs &amp;quot;component failure&amp;quot; as the root cause, and moves on. That&#39;s not root cause analysis. That&#39;s just describing what happened. The root cause is why the component failed: inadequate maintenance, incorrect installation, design limitation, contamination, or some other systemic issue that made the failure possible.&lt;/p&gt;
&lt;p&gt;Another common failure is accepting &amp;quot;human error&amp;quot; as a root cause. People make mistakes. This is not new information. If your analysis concludes that someone made a mistake, ask why that mistake was possible and why existing safeguards didn&#39;t prevent or catch it. Human error is a symptom, not a cause.&lt;/p&gt;
&lt;p&gt;Teams sometimes rush through the analysis because they&#39;re uncomfortable with the questions. Someone asks why a procedure wasn&#39;t followed, and instead of actually investigating, the team quickly blames the operator and moves on. This happens in organizations where problem-solving has become a blame-finding exercise. If your culture doesn&#39;t support honest answers, the Five Whys won&#39;t work regardless of how well you understand the technique.&lt;/p&gt;
&lt;p&gt;Some teams branch off into multiple causal chains without finishing any of them. They ask the first why, get an answer, then immediately see three more potential causes and start investigating all of them. Before long, they&#39;ve filled a whiteboard with possibilities but haven&#39;t followed any single path to a concrete root cause. Discipline yourself to investigate one chain completely before exploring alternatives.&lt;/p&gt;
&lt;h2 id=&quot;tools-and-software-for-five-whys-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#tools-and-software-for-five-whys-analysis&quot;&gt;Tools and Software for Five Whys Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You don&#39;t need specialized software to conduct a Five Whys analysis. A whiteboard, a notepad, or a simple word processing document works fine. The tool matters far less than the discipline with which you apply the method.&lt;/p&gt;
&lt;p&gt;That said, organizations that conduct frequent root cause analyses often find value in standardized digital tools. Quality management systems like ETQ, MasterControl, or Sparta Systems include Five Whys templates integrated with corrective action tracking. This integration helps ensure that the actions identified during analysis actually get completed and verified.&lt;/p&gt;
&lt;p&gt;Project management platforms can be adapted for Five Whys documentation if you configure custom workflows. The advantage here is that corrective actions automatically flow into your existing task management processes rather than living in a separate system that nobody checks.&lt;/p&gt;
&lt;p&gt;Some organizations prefer physical tools. I&#39;ve worked in plants that keep Five Whys templates on clipboards at each production line. When a problem occurs, the shift supervisor conducts the analysis right there, documents it on the physical form, and posts it on a problem-solving board where everyone can see it. This visibility reinforces the importance of root cause analysis and shares lessons learned across shifts.&lt;/p&gt;
&lt;p&gt;The best tool is the one your team will actually use consistently. If your organization already has a quality management system, use that. If you&#39;re just starting out, begin with the simplest thing that works: a shared document template and a commitment to complete one analysis per week.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-5-problem-solving-steps-process%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#what-is-the-5-problem-solving-steps-process%3F&quot;&gt;What Is the 5 Problem-Solving Steps Process?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The 5 problem-solving steps is a broader framework that incorporates the Five Whys as one component. The steps are: define the problem, analyze the root cause, develop solutions, implement corrective actions, and verify effectiveness. The Five Whys specifically addresses the second step, root cause analysis.&lt;/p&gt;
&lt;p&gt;This framework matters because root cause analysis by itself doesn&#39;t solve problems. You also need clear problem definition up front, solution development after you identify the cause, disciplined implementation, and verification that your corrective actions actually worked. Organizations sometimes do excellent Five Whys analyses but never implement the corrective actions they identify. The analysis becomes an end in itself rather than a means to improvement.&lt;/p&gt;
&lt;p&gt;Effective problem-solving requires all five steps in sequence. Rushing to solutions before you understand root causes leads to wasted effort fixing the wrong things. Identifying root causes but failing to implement solutions means nothing changes. Implementing solutions without verification means you never know if they actually worked or if the problem just hasn&#39;t recurred yet by chance.&lt;/p&gt;
&lt;h2 id=&quot;example-of-a-5-why-question-in-practice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#example-of-a-5-why-question-in-practice&quot;&gt;Example of a 5 Why Question in Practice&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What does an effective Five Whys question actually sound like? Here&#39;s the classic example from Taiichi Ohno, one of the architects of the Toyota Production System, documented in his book &amp;quot;Toyota Production System: Beyond Large-Scale Production&amp;quot; (1988, p. 17).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; A machine stopped functioning on the factory floor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why #1:&lt;/strong&gt; &amp;quot;Why did the machine stop?&amp;quot;&lt;br /&gt;
&lt;em&gt;Answer:&lt;/em&gt; There was an overload and the fuse blew.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why #2:&lt;/strong&gt; &amp;quot;Why was there an overload?&amp;quot;&lt;br /&gt;
&lt;em&gt;Answer:&lt;/em&gt; The bearing was not sufficiently lubricated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why #3:&lt;/strong&gt; &amp;quot;Why was it not lubricated sufficiently?&amp;quot;&lt;br /&gt;
&lt;em&gt;Answer:&lt;/em&gt; The lubrication pump was not pumping sufficiently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why #4:&lt;/strong&gt; &amp;quot;Why was it not pumping sufficiently?&amp;quot;&lt;br /&gt;
&lt;em&gt;Answer:&lt;/em&gt; The shaft of the pump was worn and rattling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why #5:&lt;/strong&gt; &amp;quot;Why was the shaft worn out?&amp;quot;&lt;br /&gt;
&lt;em&gt;Answer:&lt;/em&gt; There was no strainer attached and metal scrap got in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt; No strainer in the lubrication system allowing debris contamination.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Corrective action:&lt;/strong&gt; Install a strainer in the lubrication system to prevent metal scrap from entering the pump.&lt;/p&gt;
&lt;p&gt;This example demonstrates the fundamental questioning pattern. Modern Five Whys analyses typically include more detailed evidence documentation at each step (inspection reports, sensor data, maintenance logs), but the core approach of following a single causal chain to reach a systemic issue remains unchanged. Notice how the analysis moved from a symptom (blown fuse) through intermediate causes (overload, insufficient lubrication, worn shaft) to arrive at a fixable process gap (missing strainer).&lt;/p&gt;
&lt;h2 id=&quot;implementing-the-five-whys-in-your-organization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#implementing-the-five-whys-in-your-organization&quot;&gt;Implementing the Five Whys in Your Organization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to implement the Five Whys effectively, start with a pilot program rather than a company-wide rollout. Select one department or one type of problem as your initial focus. Train a small group of people thoroughly rather than providing superficial training to everyone. Conduct your first few analyses with experienced facilitation, ideally from someone who has used the method successfully in another organization.&lt;/p&gt;
&lt;p&gt;Expect the first several analyses to feel awkward. People will struggle with phrasing neutral questions. They&#39;ll want to skip ahead to solutions before finishing the analysis. They&#39;ll be uncomfortable when the questioning reveals gaps in procedures or training. This is normal. The skill develops with practice.&lt;/p&gt;
&lt;p&gt;After each analysis, conduct a brief debrief focused on the process itself. What went well? Where did we struggle? Did we gather evidence before answering, or did we speculate? Did we follow one causal chain to the end, or did we branch off into multiple paths? This reflection builds capability faster than simply conducting more analyses.&lt;/p&gt;
&lt;p&gt;Track your corrective action completion rate. If actions identified during Five Whys analyses aren&#39;t being implemented, you have an organizational problem that needs attention. Root cause analysis without follow-through is worse than no analysis at all because it creates the illusion of improvement while nothing actually changes.&lt;/p&gt;
&lt;p&gt;Give it six months before evaluating whether the method is working for your organization. You should see a reduction in recurring problems, faster resolution of new problems, and increasing confidence among frontline staff in their ability to identify and solve issues. If you&#39;re not seeing these outcomes, the problem is usually implementation rather than the method itself.&lt;/p&gt;
&lt;h2 id=&quot;measuring-whether-the-five-whys-is-working&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#measuring-whether-the-five-whys-is-working&quot;&gt;Measuring Whether the Five Whys Is Working&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;How do you know if the Five Whys is actually improving your operations? Four metrics tell the story:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem recurrence rates.&lt;/strong&gt; If you&#39;re conducting thorough root cause analyses and implementing effective corrective actions, the same problems should stop reappearing. Pull your incident data from six months before you started using the Five Whys and compare it to six months after. Look for problems that used to recur monthly or quarterly that have stopped appearing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cycle time from problem to solution.&lt;/strong&gt; As your team gets more practiced with the method, this should decrease. Early on, you might take two weeks to complete an analysis and implement corrections. After several months of practice, you should be conducting same-day or next-day analyses with corrective actions implemented within a week.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quality of corrective actions.&lt;/strong&gt; Are you implementing procedural changes, training improvements, and system modifications? Or are you repeatedly concluding that operators need to &amp;quot;be more careful&amp;quot; and issuing reminders? High-quality corrective actions address systemic issues. Low-quality corrective actions ask people to try harder without changing anything about the system they work in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Staff engagement.&lt;/strong&gt; Are frontline staff bringing problems forward more readily? Are they participating actively in analyses? Are they suggesting root causes and corrective actions? Increasing engagement signals that the method is building problem-solving capability across your organization rather than remaining a management-only activity.&lt;/p&gt;
&lt;h2 id=&quot;the-limitations-nobody-talks-about&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#the-limitations-nobody-talks-about&quot;&gt;The Limitations Nobody Talks About&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Five Whys has limitations that don&#39;t get discussed much in the literature promoting it. Understanding these limitations helps you apply the method appropriately rather than treating it as a universal solution.&lt;/p&gt;
&lt;p&gt;First, the method assumes a relatively linear cause-and-effect relationship. Many real-world problems involve complex interactions between multiple systems where causes and effects aren&#39;t clearly distinguishable. Equipment failures in modern automated systems often result from software interactions, sensor drift, mechanical wear, and operator actions all contributing simultaneously. The Five Whys struggles with this kind of complexity because it forces you to follow a single thread.&lt;/p&gt;
&lt;p&gt;Second, the technique depends entirely on the knowledge and honesty of the people answering the questions. If they don&#39;t actually know why something happened, they&#39;ll speculate. If they&#39;re afraid of identifying systemic issues that might reflect poorly on management, they&#39;ll stop at superficial answers. The Five Whys doesn&#39;t magically generate insight. It structures questioning, but the quality of answers depends on the people providing them.&lt;/p&gt;
&lt;p&gt;Third, the method can lead to what statisticians call &amp;quot;confirmation bias.&amp;quot; If your team already suspects the cause of a problem, the questions will unconsciously steer toward confirming that hypothesis rather than genuinely exploring alternatives. A facilitator aware of this bias can counteract it, but it requires conscious effort.&lt;/p&gt;
&lt;p&gt;Finally, the Five Whys doesn&#39;t help you prioritize which problems to investigate. If you have twenty recurring issues, it doesn&#39;t tell you which five deserve immediate root cause analysis and which can wait. You need a separate prioritization framework based on safety risk, financial impact, frequency, or strategic importance.&lt;/p&gt;
&lt;p&gt;These limitations don&#39;t make the method useless. They just mean you need to recognize when you&#39;re facing a problem that requires a different or additional approach.&lt;/p&gt;
&lt;h2 id=&quot;what-happens-after-the-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#what-happens-after-the-analysis&quot;&gt;What Happens After the Analysis&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Five Whys analysis is the easy part. Implementation is where most organizations struggle. You&#39;ve identified that your preventive maintenance schedule is inadequate, or your training program has gaps, or your procedures haven&#39;t been updated to match your current equipment. Now you have to actually fix these things, which requires resources, time, and organizational commitment.&lt;/p&gt;
&lt;p&gt;Effective implementation requires clear ownership. Someone needs to be specifically responsible for each corrective action, with a realistic deadline and the authority to make the necessary changes. &amp;quot;The maintenance department will handle it&amp;quot; doesn&#39;t work. &amp;quot;James will revise the PM schedule by December 15th and review it with the maintenance manager before implementation&amp;quot; does.&lt;/p&gt;
&lt;p&gt;Build verification into your corrective actions. How will you know if the changes you implemented actually solved the problem? In some cases, verification is straightforward: if the problem was equipment failures, track whether failures stop occurring. In other cases, you need to actively test: if you revised a procedure, observe someone following the new procedure to ensure it&#39;s clear and complete.&lt;/p&gt;
&lt;p&gt;Communicate the results. When a Five Whys analysis leads to improvements, tell people about it. Post the analysis and the corrective actions where staff can see them. Mention it in team meetings. This visibility serves two purposes: it demonstrates that problem-solving leads to real changes, and it shares lessons learned across your organization so other areas can benefit from what you discovered.&lt;/p&gt;
&lt;p&gt;Don&#39;t declare victory too soon. Some corrective actions take time to show results, and some problems are intermittent enough that you need several months of data to confirm they&#39;re truly resolved. Plan a follow-up review three to six months after implementation to verify effectiveness and make adjustments if needed.&lt;/p&gt;
&lt;p&gt;The Five Whys is a tool for getting to root causes. But getting to root causes only matters if you do something about them. The analysis takes thirty minutes. The real work comes after.&lt;/p&gt;
&lt;h2 id=&quot;monitor-your-corrective-actions-across-all-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/five-whys-root-cause-analysis-definition-examples/#monitor-your-corrective-actions-across-all-systems&quot;&gt;Monitor Your Corrective Actions Across All Systems&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;ve identified the root cause and implemented fixes. Now you need to verify they&#39;re working, across IT systems, OT equipment, quality databases, and maintenance platforms.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; connects them all. Whether it&#39;s legacy PLCs or modern IoT sensors, ERP systems or SCADA networks, FlowFuse brings your data together in one place. Build dashboards that track the metrics proving your solutions worked: reduced equipment failures, lower defect rates, improved maintenance compliance, or whatever KPIs matter for your specific corrective actions.&lt;/p&gt;
&lt;p&gt;Catch warning signs before problems recur. See trends that reveal whether your fixes are holding or degrading over time. Turn root cause analysis into continuous improvement with real-time monitoring.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Start connecting your systems with FlowFuse&lt;/a&gt; and prove your Five Whys analyses deliver lasting results.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/what-is-teep/</id>
        <title>What is TEEP? Calculation, Benchmarks &amp; TEEP vs OEE (2026)</title>
        <summary>If you&#39;re tracking OEE, you&#39;re only seeing half the picture.</summary>
        <updated>2025-12-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/what-is-teep/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Total Effective Equipment Performance (TEEP) is a manufacturing KPI used to understand how much of an equipment investment is actually being utilized. While most manufacturers rely on &lt;a href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#what-is-oee%3F&quot;&gt;Overall Equipment Effectiveness (OEE)&lt;/a&gt; to assess shop-floor performance, years of real-world use have revealed a critical blind spot: OEE only measures how well equipment runs &lt;em&gt;when it is scheduled to run&lt;/em&gt;. It says nothing about the many hours assets sit idle due to planning decisions, demand patterns, labor availability, or maintenance strategy.&lt;/p&gt;
&lt;p&gt;This gap matters. In many factories, equipment represents the largest capital investment on the balance sheet, yet significant capacity remains unused outside scheduled production hours. TEEP addresses this gap by extending measurement beyond scheduled production and into total calendar time—providing visibility into both operational performance and unused capacity.&lt;/p&gt;
&lt;p&gt;To understand how TEEP does this, it’s important to be precise about what the metric actually measures.&lt;/p&gt;
&lt;h2 id=&quot;what-is-teep%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#what-is-teep%3F&quot;&gt;What is TEEP?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TEEP measures the percentage of &lt;strong&gt;total calendar time&lt;/strong&gt; that equipment spends producing good parts at the correct speed. Unlike OEE, which evaluates performance only during planned production, TEEP includes &lt;strong&gt;every hour of the day&lt;/strong&gt;, whether production was scheduled or not. That means all 168 hours in a week and all 8,760 hours in a year are part of the calculation.&lt;/p&gt;
&lt;p&gt;This distinction is fundamental. If a factory operates a single shift per day, OEE evaluates only those eight scheduled hours and ignores the remaining sixteen. TEEP counts them all. As a result, TEEP reveals how much of the equipment’s full potential is actually being used—not just how well it performs during active shifts.&lt;/p&gt;
&lt;h2 id=&quot;teep-formula-and-calculation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#teep-formula-and-calculation&quot;&gt;TEEP Formula and Calculation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The math works the same way as OEE:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TEEP = Availability × Performance × Quality&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But availability now means operating time divided by total calendar time, not just scheduled time. If a production line runs 120 hours per week at full speed with no defects, it has 71.4% TEEP (120 divided by 168). The other 48 hours might be maintenance time, unplanned downtime, or time when no production was scheduled.&lt;/p&gt;
&lt;h2 id=&quot;why-teep-matters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#why-teep-matters&quot;&gt;Why TEEP Matters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TEEP matters because it connects operational performance to &lt;strong&gt;business value&lt;/strong&gt;, not just shop-floor efficiency. While OEE shows how well equipment runs during scheduled shifts, it says nothing about how much of the asset you&#39;re actually using relative to what you paid for it. TEEP fills that gap.&lt;/p&gt;
&lt;p&gt;For capital-intensive manufacturing, this difference is critical. Equipment often represents millions in investment, yet much of that capacity may sit idle due to scheduling choices, demand patterns, labor availability, or maintenance strategy. TEEP makes this visible. It answers the executive-level question: &lt;strong&gt;&amp;quot;Are we getting a return on our equipment, or is capacity hiding in plain sight?&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TEEP is especially valuable when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer demand is increasing and capacity feels tight&lt;/li&gt;
&lt;li&gt;Management is considering adding shifts or buying new equipment&lt;/li&gt;
&lt;li&gt;Capital expenditure decisions need justification&lt;/li&gt;
&lt;li&gt;Different plants or lines need to be compared at a high level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In many cases, TEEP reveals that the fastest and cheapest way to increase output is not buying new machines—but better utilizing the ones already installed. A modest TEEP improvement can unlock significant production capacity without additional capital investment.&lt;/p&gt;
&lt;p&gt;Importantly, TEEP is not about pushing equipment to run 24/7 at all costs. Instead, it provides the data needed to make &lt;strong&gt;intentional, informed decisions&lt;/strong&gt; about scheduling, staffing, maintenance, and growth.&lt;/p&gt;
&lt;h2 id=&quot;teep-vs-oee%3A-key-differences&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#teep-vs-oee%3A-key-differences&quot;&gt;TEEP vs OEE: Key Differences&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OEE and TEEP both measure equipment performance, but they look at different things. The big difference is what time period they measure against.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;OEE&lt;/th&gt;
&lt;th&gt;TEEP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it measures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How well equipment runs during scheduled time&lt;/td&gt;
&lt;td&gt;How much of total time equipment actually produces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time counted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only planned production hours&lt;/td&gt;
&lt;td&gt;Every hour (24/7, all year)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who uses it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Production supervisors and operators&lt;/td&gt;
&lt;td&gt;Executives and plant managers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical numbers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;60-85% is good&lt;/td&gt;
&lt;td&gt;30-80% depending on shifts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main question answered&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot;How efficiently did we use our scheduled time?&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;How much are we actually using this equipment?&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Here&#39;s another simple example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Your packaging line runs one 8-hour shift per day, Monday through Friday. In one week:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You scheduled 40 hours of production&lt;/li&gt;
&lt;li&gt;Equipment actually ran well for 34 hours&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your OEE: 85%&lt;/strong&gt; - Great! The production team did an excellent job during their shift.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your TEEP: 20%&lt;/strong&gt; - The equipment was productive for 34 out of 168 total hours in the week.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both numbers are correct and useful. OEE shows your production team is doing their job well. TEEP shows the equipment sits unused most of the time. Whether that&#39;s okay depends on customer demand, labor costs, and your business strategy.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-good-teep-score%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#what-is-a-good-teep-score%3F&quot;&gt;What Is a Good TEEP Score?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the most common questions manufacturers ask is: &amp;quot;What TEEP score should we target?&amp;quot; The answer depends entirely on your industry, shift strategy, and business model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Industry-Specific TEEP Benchmarks:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Continuous process industries&lt;/strong&gt; (paper mills, chemical plants, refineries): 80-90% TEEP for critical equipment. These operations are designed for 24/7 production, and high TEEP reflects the economics of continuous processing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Two-shift batch manufacturers&lt;/strong&gt; (automotive parts, packaging, electronics): 40-60% TEEP is typical. Even with excellent operational performance, running two 8-hour shifts five days per week caps theoretical maximum TEEP at 48%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Single-shift operations&lt;/strong&gt; (job shops, specialized manufacturing): 25-35% TEEP is common and often optimal. Running one 8-hour shift per day limits maximum TEEP to about 24% even with perfect execution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key insight: &lt;strong&gt;good TEEP is relative, not absolute&lt;/strong&gt;. A 35% TEEP might represent world-class performance for a single-shift custom manufacturer, while 65% TEEP could indicate serious underutilization for a continuous process line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What matters most is:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Trend analysis&lt;/strong&gt;: Is your TEEP improving or declining over time?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal benchmarking&lt;/strong&gt;: How does similar equipment compare within your facility?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Business alignment&lt;/strong&gt;: Does your TEEP support your capacity strategy and customer demand patterns?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Don&#39;t chase arbitrary TEEP targets. Instead, use TEEP to understand whether your equipment utilization matches your business strategy, identify capacity constraints before they become critical, and make informed decisions about shift additions or capital investments.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-both-metrics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#how-to-use-both-metrics&quot;&gt;How to Use Both Metrics&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most companies track both OEE and TEEP. OEE stays the main tool for production supervisors and operators who focus on running equipment well during scheduled time. TEEP gives executives information they need for planning capacity, deciding on equipment purchases, and analyzing whether to expand into new markets.&lt;/p&gt;
&lt;p&gt;To calculate TEEP correctly, you need to track time carefully. Many manufacturing systems already sort downtime into planned and unplanned categories for OEE. TEEP needs more detail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scheduled production time&lt;/strong&gt;: When equipment runs or could start running right away&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planned maintenance&lt;/strong&gt;: Regular maintenance windows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changeovers&lt;/strong&gt;: Time spent switching between different products&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No orders&lt;/strong&gt;: Equipment sits idle because not enough customers want products&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational limits&lt;/strong&gt;: Problems with other equipment, not enough workers, or other constraints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without clear categories, TEEP can unfairly punish good operational decisions. Equipment that creates bottlenecks should show high TEEP. Other equipment may correctly show lower numbers.&lt;/p&gt;
&lt;h2 id=&quot;real-world-examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#real-world-examples&quot;&gt;Real-World Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TEEP works best in industries where equipment can run around the clock. Paper mills, chemical plants, and steel factories typically target higher TEEP values for their main production equipment since continuous operation makes business sense for these processes.&lt;/p&gt;
&lt;p&gt;Industries that make distinct products in batches usually see lower numbers. This makes sense when you think about it: a factory running two eight-hour shifts, five days per week, can only reach about 48% TEEP even if everything runs perfectly during those scheduled hours.&lt;/p&gt;
&lt;p&gt;The automotive industry shows why context matters. Assembly lines often run two shifts per day. Even with excellent operational performance during scheduled production time, TEEP numbers naturally stay lower. This reflects intentional business decisions about shift schedules, labor costs, and maintenance planning rather than poor performance.&lt;/p&gt;
&lt;h2 id=&quot;common-mistakes-to-avoid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#common-mistakes-to-avoid&quot;&gt;Common Mistakes to Avoid&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Several problems come up when companies use TEEP incorrectly. One major mistake is using TEEP to judge daily operations. Production workers cannot control customer demand or high-level scheduling decisions. Holding supervisors responsible for TEEP creates bad incentives to build unnecessary inventory or skip planned maintenance.&lt;/p&gt;
&lt;p&gt;Another common error is ignoring the bigger picture. Equipment designed to handle product changes, quality testing, or work with other equipment should not be compared to equipment that runs continuously. A 35% TEEP might be the best possible number for a packaging line that serves multiple production lines.&lt;/p&gt;
&lt;p&gt;Finally, many companies make the mistake of treating TEEP as a fixed target. TEEP helps you compare performance over time or across similar equipment. A dropping TEEP trend means you should investigate. But any single TEEP number needs context to understand what it means.&lt;/p&gt;
&lt;h2 id=&quot;using-teep-for-capacity-planning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#using-teep-for-capacity-planning&quot;&gt;Using TEEP for Capacity Planning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TEEP helps most when planning capacity. When customer demand gets close to what you can produce, companies face a big decision: spend money to expand capacity or accept slower growth. TEEP analysis clarifies this choice by showing how much extra capacity exists in current equipment.&lt;/p&gt;
&lt;p&gt;A factory with 65% TEEP across major equipment could theoretically increase production by 54% without buying new equipment, assuming customer demand exists and operational problems can be solved. Whether this capacity can actually be used depends on shift schedules, worker availability, maintenance needs, and product mix—but TEEP shows the theoretical maximum.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-teep-measurement&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#setting-up-teep-measurement&quot;&gt;Setting Up TEEP Measurement&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Companies that want accurate TEEP need good data collection systems. Writing down times by hand produces unreliable results. Automated data capture from equipment computers, control systems, or manufacturing software provides the foundation for accurate calculations.&lt;/p&gt;
&lt;p&gt;The money spent on measurement systems should match decision-making needs. Companies making frequent capacity investment decisions benefit from real-time TEEP monitoring. Organizations with stable capacity and clear bottlenecks might find quarterly manual calculations work fine.&lt;/p&gt;
&lt;p&gt;Building TEEP dashboards has become much simpler with modern tools. FlowFuse offers a practical solution for companies that want real-time equipment monitoring without complex programming. The platform bridges the gap between OT (Operational Technology) on the factory floor and IT systems in the office. It connects directly to your equipment—whether through &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;PLCs, SCADA systems&lt;/a&gt;, or &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;machine controllers and MES platforms&lt;/a&gt;—and creates visual dashboards that track performance metrics. You can see how straightforward the process is by looking at their &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;OEE dashboard blueprint&lt;/a&gt;. The same approach works for TEEP—connect your data sources, set up the calculations, and view your equipment utilization in real-time. This makes professional-grade monitoring accessible even for smaller manufacturers or companies without dedicated programming staff.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Want to see how TEEP monitoring would work for your specific equipment and production environment? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; with FlowFuse to explore how you can track equipment utilization, identify capacity opportunities, and make data-driven decisions about your manufacturing assets.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-bottom-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/what-is-teep/#the-bottom-line&quot;&gt;The Bottom Line&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TEEP extends equipment measurement from operational efficiency to overall asset use. It does not replace OEE but adds to it by answering questions OEE cannot answer. When used carefully with proper context, TEEP gives manufacturing leaders clear visibility into total equipment productivity. It helps inform capacity investment decisions with solid numbers. The value is not in achieving high percentages but in understanding what those percentages reveal about equipment use, customer demand, and operational constraints.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/</id>
        <title>FlowFuse 2.25: Interacting with MCP Resources in FlowFuse Expert, Improved Update Scheduling, and lots of UI improvements!</title>
        <summary>FlowFuse 2.25: Interacting with MCP Resources in FlowFuse Expert, Improved Update Scheduling, and lots of UI improvements!</summary>
        <updated>2025-12-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release comes with some big updates for the FlowFuse Expert.&lt;/p&gt;
&lt;h2 id=&quot;interact-with-mcp-resources-in-flowfuse-expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#interact-with-mcp-resources-in-flowfuse-expert&quot;&gt;Interact with MCP Resources in FlowFuse Expert&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of MCP in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-in-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[FlowFuse Expert Interface]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mcp/&quot;&gt;MCP nodes&lt;/a&gt; make is super easy to extend AI Agents with tools and resources in your environment. With this release, we&#39;re introducing the ability to interact your MCP servers directly within the FlowFuse Expert.&lt;/p&gt;
&lt;p&gt;Previously, when setting up an MCP server in FlowFuse, you would first designate your tools, resources, and servers in side of Node-RED using the MCP nodes. Then, to interact with them, you needed a separate tool like VSCode to query and perform operations.&lt;/p&gt;
&lt;p&gt;We want you to be able to access your resources as quickly and easily as possible, and reduce the manual overhead involved in managing and querying your MCP resources.&lt;/p&gt;
&lt;p&gt;We&#39;ve greatly simplified this process. You can now set everything up in Node-RED and then use the FlowFuse expert to designate your tools and interact with them, without ever leaving FlowFuse. This will speed you up and simplify your operations.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert-assistant-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#flowfuse-expert-assistant-in-node-red&quot;&gt;FlowFuse Expert Assistant in Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;FlowFuse Expert Assistant in Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-assistant-nr.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[FlowFuse Expert UI]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We&#39;re very excited to announce that all Node-RED users can now use our FlowFuse Expert Assistant. The ASsistant will help you create Function nodes, Template nodes, and explain highlighted flows using the Flow Explainer.&lt;/p&gt;
&lt;p&gt;Previously, this was only available in Node-RED managed directly by the FlowFuse platform. Now everyone using Node-RED, whether they are a FlowFuse user or not, can make use of this technology and speed the development of their Node-RED workflows.&lt;/p&gt;
&lt;p&gt;You will need an account on FlowFuse Cloud to connect it to, but for this release, it does &lt;em&gt;not&lt;/em&gt; require a paid subscription to use.&lt;/p&gt;
&lt;p&gt;Check the FlowFuse Expert Assistant docs for &lt;a href=&quot;https://flowfuse.com/docs/user/expert/#flowfuse-assistant-plugin&quot;&gt;how to get started&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improved-update-scheduling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#improved-update-scheduling&quot;&gt;Improved Update Scheduling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of Scheduled Updates UI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/updates.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Scheduled Updates Interface]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We added the ability to schedule updates for your instances in the last release. Based on user feedback, we&#39;ve now also added the ability to schedule restarting of your instance regardless of whether an update is available.&lt;/p&gt;
&lt;h2 id=&quot;lots-of-small-updates-for-a-better-user-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#lots-of-small-updates-for-a-better-user-experience&quot;&gt;Lots of small updates for a better user experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When we plan our releases, we look for what will make good headlines in our release annoucements - the big, shiny features that can get lots of attention. Sometimes we also take an opportunity to clear lots of little issues that ultimately are less headline-worthy, but all make for a better user experience.&lt;/p&gt;
&lt;p&gt;For example, this release sees lots of small improvements to the FlowFuse Tables user experience; adding the ability to refresh the displayed data, more accessible column table names, an improved layout. Nothing to set the socials buzzing, but genuine quality of life improvements to our users.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.25 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.25.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Reach out on GitHub or social media!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/</id>
        <title>MQTT vs Kafka: Complete Comparison Guide 2026</title>
        <summary>Compare features, performance, and use cases to choose the right protocol</summary>
        <updated>2025-12-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Building IoT systems means making hard choices about how messages flow through your infrastructure. Apache Kafka and MQTT couldn&#39;t be more different in their approaches. MQTT came from the world of sensors and resource-constrained devices. Kafka was designed to push massive data streams between backend systems. Getting this choice right early determines whether your architecture scales smoothly or hits a wall.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-mqtt-different&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#what-makes-mqtt-different&quot;&gt;What Makes MQTT Different&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT (Message Queuing Telemetry Transport) showed up in 1999 when engineers needed to monitor oil pipelines with SCADA systems over unreliable satellite links. The whole point was squeezing messages through terrible networks without killing battery life.&lt;/p&gt;
&lt;p&gt;The protocol uses binary encoding with headers as small as 2 bytes. That&#39;s it. This matters when you&#39;re running on an ESP32 with 520KB of RAM or sending data over a 2G connection that costs per kilobyte. MQTT runs over TCP/IP and supports TLS when you need encryption.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image: How MQTT Works&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s how it works: A central broker sits in the middle. Devices publish messages to topics like &lt;code&gt;factory/line-1/temperature&lt;/code&gt;. Other devices subscribe to those topics. The broker figures out who gets what. Topics use forward slashes to create hierarchies, so you can subscribe to &lt;code&gt;factory/#&lt;/code&gt; and catch everything happening in the factory. You can also use wildcards: &lt;code&gt;#&lt;/code&gt; matches multiple levels (like &lt;code&gt;factory/# &lt;/code&gt;for everything under factory), while &lt;code&gt;+&lt;/code&gt; matches exactly one level (like &lt;code&gt;sensors/+/temperature&lt;/code&gt; for temperature readings from any single sensor).&lt;/p&gt;
&lt;p&gt;MQTT has three Quality of Service levels:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 0&lt;/strong&gt; - Fire and forget. Send the message once, hope it arrives. No acknowledgment, no retry. Fast but unreliable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 1&lt;/strong&gt; - At least once delivery. The broker acknowledges receipt and retries if needed. You might get duplicates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 2&lt;/strong&gt; - Exactly once through a four-way handshake. Slowest but guaranteed.&lt;/p&gt;
&lt;p&gt;Pick based on what you&#39;re sending. Temperature readings every 10 seconds? QoS 0 is fine. Critical alarm messages? QoS 2.&lt;/p&gt;
&lt;h2 id=&quot;how-kafka-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#how-kafka-works&quot;&gt;How Kafka Works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LinkedIn built Kafka in 2011 because they were drowning in activity streams and operational metrics. Traditional message queues couldn&#39;t keep up. So they designed something that acts more like a distributed database than a message broker.&lt;/p&gt;
&lt;p&gt;Kafka organizes everything into topics, and topics split into partitions. Each partition is just an ordered log of messages that never changes once written. Producers append messages to the end. Consumers track where they are in each partition using offsets. Multiple producers and consumers can hammer different partitions simultaneously, which is how Kafka gets ridiculous throughput.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image: How Kafka Works&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kafka.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The architecture spreads partitions across multiple broker servers. Each partition gets replicated to other brokers based on your replication factor. If a broker crashes, another one takes over for its partitions immediately. No data loss, no downtime.&lt;/p&gt;
&lt;p&gt;Unlike MQTT, messages don&#39;t disappear after delivery. Everything writes to disk. You configure retention policies—keep messages for 7 days, 30 days, or forever. This means you can replay messages, let new consumers read historical data, or reprocess everything if your analytics code had a bug.&lt;/p&gt;
&lt;p&gt;Early Kafka needed Apache Zookeeper for cluster coordination, which added complexity. Recent versions support KRaft mode that removes this dependency, though many production systems still run Zookeeper.&lt;/p&gt;
&lt;h2 id=&quot;the-real-differences&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#the-real-differences&quot;&gt;The Real Differences&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;architecture-philosophy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#architecture-philosophy&quot;&gt;Architecture Philosophy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT keeps things simple with a central broker. Devices connect, the broker routes messages, everyone&#39;s happy. You can get started with a single Raspberry Pi running Mosquitto. The 2-byte headers and compact binary format mean your sensor data flows efficiently even on constrained networks.&lt;/p&gt;
&lt;p&gt;Kafka is distributed by design. Topics partition across brokers. Consumers track offsets themselves. Everything replicates for fault tolerance. You need coordination infrastructure (Zookeeper or KRaft), multiple brokers for production, and someone who knows distributed systems. But this complexity buys you throughput that single-broker systems simply can&#39;t match.&lt;/p&gt;
&lt;h3 id=&quot;performance-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#performance-reality&quot;&gt;Performance Reality&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT delivers messages in milliseconds. It runs on microcontrollers with kilobytes of RAM. A sensor reading might be 10-20 bytes including protocol overhead. A decent broker handles thousands to tens of thousands of messages per second, which works fine when you have hundreds of thousands of devices sending data every few seconds.&lt;/p&gt;
&lt;p&gt;Kafka sacrifices latency for volume. Messages take tens to hundreds of milliseconds because of disk writes, replication, and consumer polling. But a single broker can handle hundreds of thousands of messages per second. Clusters process billions daily. You need real hardware—multiple cores, 32GB+ memory, fast SSDs—but you get data movement at enterprise scale.&lt;/p&gt;
&lt;h3 id=&quot;how-messages-get-delivered&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#how-messages-get-delivered&quot;&gt;How Messages Get Delivered&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT&#39;s three QoS levels give you options. QoS 0 is fast but lossy. QoS 1 guarantees delivery but might duplicate. QoS 2 does exactly-once with a four-way handshake. Brokers can queue messages for offline subscribers, but they&#39;re not designed for long-term storage.&lt;/p&gt;
&lt;p&gt;Kafka writes everything to disk based on your retention policy. Producers pick acknowledgment levels: wait for the leader broker (fast, less safe) or wait for all replicas (slower, fully durable). Consumers commit offsets after processing messages. Modern Kafka supports exactly-once semantics through transactions and idempotent producers. The persistence model enables message replay and handles consumer failures completely differently than MQTT.&lt;/p&gt;
&lt;h3 id=&quot;running-this-stuff-in-production&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#running-this-stuff-in-production&quot;&gt;Running This Stuff in Production&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Setting up an MQTT broker is straightforward. You can start with something like Mosquitto for development, or choose from production-ready brokers that support clustering and high availability. Configure authentication, add redundancy as needed, and monitor connection counts, message rates, and queue depths—most brokers expose metrics via REST APIs or monitoring endpoints.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FlowFuse includes a managed MQTT broker built right into the platform—no separate infrastructure to set up or maintain. It connects directly with your Node-RED flows, so you can publish and subscribe to topics without leaving the environment. Check out the &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-3%3A-set-up-mqtt-with-flowfuse&quot;&gt;details&lt;/a&gt; to see how it works.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kafka demands more. You need at least three brokers plus coordination services. Monitor partition distribution, replication lag, consumer group status, disk usage. Plan capacity for both storage and network bandwidth. Rolling upgrades require care. Partition reassignment needs coordination. The learning curve is real, but the system handles failures gracefully once you understand it.&lt;/p&gt;
&lt;h3 id=&quot;where-to-use-each-one&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#where-to-use-each-one&quot;&gt;Where to Use Each One&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MQTT dominates in manufacturing plants with sensor networks, building automation, remote sites on cellular connections, and fleet tracking. It&#39;s the right call when devices have limited CPU and memory, networks constrain bandwidth, you&#39;re dealing with thousands of messages per second, and you don&#39;t need long-term storage.&lt;/p&gt;
&lt;p&gt;Kafka powers financial transaction processing, e-commerce backends, infrastructure monitoring at scale, and data engineering pipelines. Use it when message volumes hit hundreds of thousands per second, multiple systems need independent access to the same data stream, you need replay capabilities, or you&#39;re feeding data into analytics platforms.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Most real systems use both. MQTT handles the edge, Kafka moves data between central systems. You see this pattern everywhere—MQTT at factory sites, Kafka in the data center.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;making-the-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#making-the-choice&quot;&gt;Making the Choice&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how to think about it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pick MQTT when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your devices are resource-constrained (microcontrollers, embedded systems)&lt;/li&gt;
&lt;li&gt;Network bandwidth is limited or expensive&lt;/li&gt;
&lt;li&gt;You&#39;re handling thousands of messages per second&lt;/li&gt;
&lt;li&gt;Simple deployment matters&lt;/li&gt;
&lt;li&gt;You need efficient edge device communication&lt;/li&gt;
&lt;li&gt;Long-term message storage isn&#39;t a requirement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pick Kafka when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Message volumes hit hundreds of thousands per second or more&lt;/li&gt;
&lt;li&gt;Multiple applications need independent access to message streams&lt;/li&gt;
&lt;li&gt;You need message replay or event sourcing capabilities&lt;/li&gt;
&lt;li&gt;Stream processing is part of the architecture&lt;/li&gt;
&lt;li&gt;Integration with big data tools matters&lt;/li&gt;
&lt;li&gt;Your ops team knows distributed systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither is &amp;quot;better.&amp;quot; They solve different problems. Your requirements drive the decision.&lt;/p&gt;
&lt;h2 id=&quot;integrating-mqtt-and-kafka&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#integrating-mqtt-and-kafka&quot;&gt;Integrating MQTT and Kafka&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned, real production systems don’t choose between these—they use both. Devices and sensors typically publish data over MQTT, while analytics platforms, data lakes, and stream processors consume events from Kafka. The real challenge lies in bridging the two reliably and cleanly.&lt;/p&gt;
&lt;p&gt;Most teams write custom bridge services or deploy Kafka Connect with MQTT source connectors. Custom bridges give you complete control but require development and maintenance. Kafka Connect reduces code but adds configuration complexity, especially when you need transformation logic beyond simple field mapping.&lt;/p&gt;
&lt;p&gt;FlowFuse takes a different approach using Node-RED&#39;s visual programming model. &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka&lt;/a&gt; nodes connect through flows that define routing and transformation logic. The platform manages protocol connections and flow execution without separate bridge infrastructure.&lt;/p&gt;
&lt;p&gt;As mentioned before, FlowFuse includes a managed MQTT broker built directly into the platform. Beyond MQTT and Kafka, it supports industrial protocols like Modbus, OPC UA, and HTTP. Device connections, message processing, and Kafka integration all happen in one environment. You get built-in version control, deployment management, team collaboration, and much more.&lt;/p&gt;
&lt;p&gt;FlowFuse offers a free trial for testing MQTT-Kafka workflows. &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Start building&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;schedule a consultation&lt;/a&gt; to discuss your specific needs.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/kafka-vs-mqtt/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT and Kafka solve different problems. MQTT gives you efficient device connectivity with minimal overhead. Kafka delivers high-throughput event streaming with persistence and replay.&lt;/p&gt;
&lt;p&gt;Understanding these differences helps you pick the right tool for the job. Most production systems use both, leveraging each where it provides the most value. Base your decision on message volumes, device capabilities, operational requirements, and team expertise—not on whatever&#39;s trending on Hacker News.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/</id>
        <title>Node-RED Buffer Parser Guide: Decode Modbus and Industrial Device Data</title>
        <summary>A practical guide to visual buffer parsing in Node-RED</summary>
        <updated>2025-12-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Legacy industrial devices communicate in bytes. Your temperature sensor doesn&#39;t send you &lt;code&gt;{&amp;quot;temp&amp;quot;: 23.5}&lt;/code&gt; - it sends you &lt;code&gt;[1, 3, 4, 1, 44, 0, 200, 190, 125]&lt;/code&gt;. Those numbers are meaningless unless you know how to decode them.&lt;/p&gt;
&lt;p&gt;This is what makes working with legacy PLCs and Modbus sensors challenging. You&#39;re not dealing with modern APIs that return JSON. You&#39;re dealing with raw binary data where byte 3 might be temperature and byte 4 might be humidity, and if you read them in the wrong order, everything breaks.&lt;/p&gt;
&lt;p&gt;Node-RED&#39;s Buffer Parser node solves this problem. Instead of writing JavaScript to manually decode every buffer, you configure it once visually and it handles the conversion automatically. In this article, we&#39;ll learn how to use this node effectively.&lt;/p&gt;
&lt;h2 id=&quot;understanding-buffer-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#understanding-buffer-data&quot;&gt;Understanding Buffer Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When your Modbus sensor responds to a query, Node-RED shows you something like this in the debug panel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1, 3, 4, 1, 44, 0, 200, 190, 125]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nine bytes. Each one is a number between 0 and 255. This data is completely meaningless without context.&lt;/p&gt;
&lt;p&gt;Byte 0 might be a device address. Bytes 3 and 4 together might encode temperature. But the buffer itself doesn&#39;t tell you any of this - you need the device manual to figure out what goes where.&lt;/p&gt;
&lt;p&gt;Take bytes 3 and 4: &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;44&lt;/code&gt;. If you&#39;re supposed to read them as a 16-bit integer, that&#39;s either 300 or 11265 depending on byte order. If the device uses a scale factor of 10, the actual temperature could be 30.0°C or 1126.5°C. Get any part of this wrong and your dashboard shows nonsense.&lt;/p&gt;
&lt;p&gt;So why do devices work this way? Why not just send &lt;code&gt;{&amp;quot;temperature&amp;quot;: 30.0}&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;That JSON message takes 21 bytes. The same information in binary takes 2 bytes. When you&#39;re on a serial connection running at 9600 baud, sending thousands of sensor readings per day, those extra bytes add up fast.&lt;/p&gt;
&lt;p&gt;More importantly, this is how industrial hardware has worked since 1979. Modbus was designed when PLCs had kilobytes of memory. Modern factories still run equipment from the 90s. The protocol isn&#39;t going to change because it would be more convenient for us.&lt;/p&gt;
&lt;p&gt;You work with what&#39;s on the factory floor, this means you need to parse buffers.&lt;/p&gt;
&lt;h2 id=&quot;example%3A-temperature-and-humidity-sensor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#example%3A-temperature-and-humidity-sensor&quot;&gt;Example: Temperature and Humidity Sensor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suppose you have a temperature and humidity sensor connected via Modbus RTU. When you query it for data, you get this buffer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1, 3, 4, 1, 44, 0, 200, 190, 125]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The device manual says this buffer breaks down as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Byte 0: Device address (1)&lt;/li&gt;
&lt;li&gt;Byte 1: Modbus function code (3 = read holding registers)&lt;/li&gt;
&lt;li&gt;Byte 2: Data length in bytes (4)&lt;/li&gt;
&lt;li&gt;Bytes 3-4: Temperature reading&lt;/li&gt;
&lt;li&gt;Bytes 5-6: Humidity reading&lt;/li&gt;
&lt;li&gt;Bytes 7-8: CRC checksum&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need to extract temperature and humidity. Everything else is Modbus protocol overhead.&lt;/p&gt;
&lt;p&gt;The manual also specifies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Temperature: 16-bit unsigned integer, big-endian, divide by 10 for actual value in °C&lt;/li&gt;
&lt;li&gt;Humidity: 16-bit unsigned integer, big-endian, divide by 10 for actual value in %RH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without Buffer Parser, you&#39;d write a function node like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-100&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-100&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; temperature &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readUInt16BE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; humidity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readUInt16BE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; humidity &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-100&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This works, but it&#39;s also fragile. When you need to add a pressure reading next month, you&#39;re editing code and hoping you don&#39;t break the offset calculations. When someone else looks at this flow, they have no idea what&#39;s happening without reading the function and if they don&#39;t understand JavaScript, they&#39;re stuck.&lt;/p&gt;
&lt;p&gt;Buffer Parser turns this into configuration you can see and modify without touching code. Let&#39;s walk through a practical example.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But before you start, make sure you have a Node-RED instance running on your edge device. The fastest, easiest, and most production-ready way is using FlowFuse. If you don&#39;t have an account yet, create one with our &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;free trial&lt;/a&gt;. FlowFuse simplifies managing remote instances and provides the ability to create hosted instances—no matter how many you need to manage, it makes it easy. There are no deployment headaches either; everything is managed by FlowFuse with built-in security. You&#39;ll also get access to tools such as DevOps pipelines, snapshots for recovery, audit logs, real-time collaboration with granular role-based access control (RBAC), and much more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;setting-up-the-buffer-parser&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#setting-up-the-buffer-parser&quot;&gt;Setting Up the Buffer Parser&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Buffer Parser node is part of the &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt; package. To install it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the menu icon (three horizontal lines) in the top-right corner&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;building-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#building-the-flow&quot;&gt;Building the Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;s create a flow to parse the buffer data. For this example, we&#39;ll use an Inject node to simulate Modbus data, so while reading you can follow along and learn.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node from the palette onto the canvas&lt;/li&gt;
&lt;li&gt;Double-click the Inject node to open its configuration&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;msg.payload&lt;/strong&gt; to &amp;quot;Buffer&amp;quot; from the dropdown&lt;/li&gt;
&lt;li&gt;In the field, enter: &lt;code&gt;[1, 3, 4, 1, 44, 0, 200, 190, 125]&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED Inject node configuration showing payload set to a Buffer array for simulating data.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/simulate-data-inject.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED Inject node configuration showing payload set to a Buffer array for simulating data.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Buffer Parser&lt;/strong&gt; node from the palette onto the canvas&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect the Inject node output to the Buffer Parser node input&lt;/li&gt;
&lt;li&gt;Connect the Buffer Parser node output to the Debug node input&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;configuring-the-buffer-parser&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#configuring-the-buffer-parser&quot;&gt;Configuring the Buffer Parser&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;s configure the Buffer Parser node to extract temperature and humidity.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Double-click the &lt;strong&gt;Buffer Parser&lt;/strong&gt; node to open its configuration panel&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Buffer Parser Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/buffer-parser.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You&#39;ll see several fields. Most of them you can ignore for basic parsing. Here&#39;s what matters:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Property&lt;/strong&gt;: Leave this set to &lt;code&gt;msg.payload&lt;/code&gt;. This tells the node where to find your buffer data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Specification:&lt;/strong&gt; Keep this set to UI Specification. This is the visual method, allowing you to configure everything directly within the node.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Result Type&lt;/strong&gt;: Set this to &amp;quot;Key/value&amp;quot;. This gives you clean JSON output like &lt;code&gt;{&amp;quot;temperature&amp;quot;: 30.0, &amp;quot;humidity&amp;quot;: 20.0}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Byte Swap&lt;/strong&gt;: Leave this set to &amp;quot;No swap&amp;quot; for now. Byte swapping reorders bytes within multi-byte values and is only needed when your device stores data in an unusual format that doesn&#39;t match standard big-endian or little-endian conventions. If you&#39;ve selected the correct endianness (like uint16be or uint16le) and values still look wrong, you might need swap16 (for 16-bit values), swap32 (for 32-bit values), or swap64 (for 64-bit values). Most devices won&#39;t require this.&lt;/p&gt;
&lt;p&gt;Now let&#39;s configure the actual data extraction.&lt;/p&gt;
&lt;h2 id=&quot;extracting-temperature&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#extracting-temperature&quot;&gt;Extracting Temperature&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s add the first field to extract temperature from bytes 3-4.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;add&lt;/strong&gt; button at the bottom of the configuration panel to create a new row in &lt;strong&gt;buffer parser&lt;/strong&gt; node&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&#39;ll see several fields appear in the row. Let&#39;s fill them in:&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;temperature&lt;/code&gt;. This is what you&#39;ll see in your output JSON.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Type&lt;/strong&gt; dropdown, select &lt;code&gt;uint16be&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This breaks down as:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uint16&lt;/code&gt; = 16-bit unsigned integer (positive values only)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;be&lt;/code&gt; = big-endian (reads bytes in order: first byte is high, second is low)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The manual specified &amp;quot;16-bit unsigned integer, big-endian&amp;quot; so this is a direct match&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Offset&lt;/strong&gt; field, enter &lt;code&gt;3&lt;/code&gt;. Temperature data starts at byte 3. Offset counts from zero, so byte 0 is first, byte 3 is fourth.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Length&lt;/strong&gt; field, enter &lt;code&gt;1&lt;/code&gt;. We&#39;re reading one value, not an array of values. Length stays at 1 for single values.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Scale&lt;/strong&gt; field, enter &lt;code&gt;0.1&lt;/code&gt;. Here&#39;s the important part: the Buffer Parser &lt;strong&gt;multiplies&lt;/strong&gt; by the scale value, so to divide by 10, you need to multiply by 0.1. Raw value 300 × 0.1 = 30.0.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Beyond simple multiplication, the Buffer Parser also supports scale equations for more complex transformations. You can use operators like &amp;gt;&amp;gt; for bit shifting (e.g., &amp;gt;&amp;gt;4 to shift right 4 bits), + or - for offsets (e.g., +42 to add 42), / or * for division/multiplication, ** for exponents, and comparison operators like ==, !=, &amp;gt;, &amp;lt; for boolean results. These equations are applied after any mask, giving you powerful options for handling bit-packed data or applying formulas without writing JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&#39;s verify this works with a simple calculation. Bytes 3 and 4 in our buffer are &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;44&lt;/code&gt;. Big-endian means we read them in order: (1 × 256) + 44 = 300 in decimal. Multiplied by 0.1 gives 30.0°C. Perfect.&lt;/p&gt;
&lt;h2 id=&quot;extracting-humidity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#extracting-humidity&quot;&gt;Extracting Humidity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;s add the second field to extract humidity from bytes 5-6.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;add&lt;/strong&gt; button again to create a second row&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Name&lt;/strong&gt; field, enter &lt;code&gt;humidity&lt;/code&gt;. This will appear as the key in your output JSON.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Type&lt;/strong&gt; dropdown, select &lt;code&gt;uint16be&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Same as temperature:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;uint16&lt;/code&gt; = 16-bit unsigned integer (no negative values)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;be&lt;/code&gt; = big-endian (reads bytes in order)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Offset&lt;/strong&gt; field, enter &lt;code&gt;5&lt;/code&gt;. Humidity data starts at byte 5.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Length&lt;/strong&gt; field, enter &lt;code&gt;1&lt;/code&gt;. We&#39;re reading a single humidity value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Scale&lt;/strong&gt; field, enter &lt;code&gt;0.1&lt;/code&gt;. Again, multiply by 0.1 to effectively divide by 10.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Buffer Parser configuration rows defining temperature and humidity extraction using uint16be with offsets and scale values.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/buffer-parser-temp-and-hum.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Buffer Parser configuration rows defining temperature and humidity extraction using uint16be with offsets and scale values.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&#39;s verify this. Bytes 5 and 6 are &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;200&lt;/code&gt;. Big-endian reads them in order: (0 × 256) + 200 = 200. Multiplied by 0.1 = 20.0% RH. Perfect.&lt;/p&gt;
&lt;h2 id=&quot;testing-the-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#testing-the-configuration&quot;&gt;Testing the Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;s test if everything works correctly.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; in the top-right corner of the Node-RED editor&lt;/li&gt;
&lt;li&gt;Click the button on the left side of the Inject node to trigger it&lt;/li&gt;
&lt;li&gt;Open the Debug panel on the right side of the editor&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your Buffer Parser output should look like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-413&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-413&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;humidity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20.0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-413&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This example should work as shown, but with your actual device data, the output may differ. If the values in your JSON don&#39;t match what you expect, you&#39;re likely running into one of a few common issues. Here&#39;s how to recognize and fix them.&lt;/p&gt;
&lt;p&gt;If your values are way off—for example, you expect 300 but see 11265, or expect 100 but see 25600—you&#39;ve got the endianness backwards. Change &lt;code&gt;int16le&lt;/code&gt; to &lt;code&gt;int16be&lt;/code&gt; (or vice versa) in the Type field. Alternatively, try setting Byte Swap to &lt;code&gt;swap16&lt;/code&gt; (or &lt;code&gt;swap32&lt;/code&gt;/&lt;code&gt;swap64&lt;/code&gt; for larger data types).&lt;/p&gt;
&lt;p&gt;If you&#39;re seeing negative numbers when you know the value should be positive, you&#39;re using signed integers when you need unsigned. Change &lt;code&gt;int16&lt;/code&gt; to &lt;code&gt;uint16&lt;/code&gt; (or &lt;code&gt;int32&lt;/code&gt; to &lt;code&gt;uint32&lt;/code&gt;) in the Type field.&lt;/p&gt;
&lt;p&gt;If your values are exactly 256 times too large or too small, you&#39;re using the wrong data type size. If you&#39;re using &lt;code&gt;int8&lt;/code&gt; but the device sends 16-bit values, change it to &lt;code&gt;int16be&lt;/code&gt; or &lt;code&gt;int16le&lt;/code&gt;. If you&#39;re using &lt;code&gt;int16&lt;/code&gt; but the device sends 32-bit values, change it to &lt;code&gt;int32be&lt;/code&gt; or &lt;code&gt;int32le&lt;/code&gt;. Check your device manual for the correct bit size.&lt;/p&gt;
&lt;p&gt;If you&#39;re getting raw values instead of scaled values (for example, 300 instead of 30.0), it means you either forgot to set the Scale field or set it incorrectly. If the device manual says ‘divide by 10,’ enter 0.1 in the Scale field (not 10). Remember: the Buffer Parser multiplies by the scale, so to divide by 10, you must multiply by 0.1&lt;/p&gt;
&lt;p&gt;If every number looks completely wrong, recount your offsets carefully. Check each Offset value and verify against your device manual. Remember that byte 0 is first, byte 1 is second, byte 3 is fourth, and so on. The most common mistake is being off by one byte.&lt;/p&gt;
&lt;p&gt;If you&#39;re getting only one value when the device sends multiple, check the Length field. If your device sends an array of 5 temperature readings starting at byte 10, set Offset to &lt;code&gt;10&lt;/code&gt; and Length to &lt;code&gt;5&lt;/code&gt;. The node will return an array of values instead of a single value.&lt;/p&gt;
&lt;h2 id=&quot;what-about-those-other-fields%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#what-about-those-other-fields%3F&quot;&gt;What About Those Other Fields?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The configuration screen has more fields we didn&#39;t touch:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bit Offset&lt;/strong&gt; only matters when you&#39;re using the &lt;code&gt;bool&lt;/code&gt; type to extract a single bit from a byte. This field is only visible when the bool type is selected. If you need to check whether bit 3 of byte 7 is set (like a &amp;quot;pump running&amp;quot; status flag), you&#39;d set Offset to 7, Type to bool, and Bit Offset to 3. For reading whole numbers, ignore this field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mask&lt;/strong&gt; is for when multiple values are packed into the same byte. Industrial protocols do this to save space - why waste 8 bits on a simple on/off flag when you can pack eight flags into one byte? If bits 0-3 hold one sensor reading and bits 4-7 hold another, you use masks like &lt;code&gt;0x0F&lt;/code&gt; (binary: 00001111, lower 4 bits) and &lt;code&gt;0xF0&lt;/code&gt; (binary: 11110000, upper 4 bits) to extract each value separately. You&#39;ll know when you need this because the manual will say something like &amp;quot;status bits 0-3 contain pump speed, bits 4-7 contain valve position.&amp;quot;&lt;/p&gt;
&lt;p&gt;For more details on the Buffer Parser node, you can also explore the official &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-buffer-parser&quot;&gt;Buffer Parser node documentation&lt;/a&gt; — it&#39;s comprehensive, well-maintained, and a great reference when working with more advanced parsing options.&lt;/p&gt;
&lt;h2 id=&quot;when-you-need-more-complex-parsing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#when-you-need-more-complex-parsing&quot;&gt;When You Need More Complex Parsing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Buffer Parser handles most industrial protocols, but not everything.&lt;/p&gt;
&lt;p&gt;If you need conditional parsing where the structure changes based on values in the buffer itself, you&#39;ll need JavaScript. For example, if byte 2 tells you how many temperature readings follow and that number varies, Buffer Parser can&#39;t handle variable-length structures dynamically.&lt;/p&gt;
&lt;p&gt;If you&#39;re dealing with bit-packed data where individual bits within bytes have meaning (common in PLC memory maps), you can use the &lt;code&gt;bool&lt;/code&gt; type with Bit Offset, but extracting many bits gets tedious. Sometimes a function node doing bitwise operations is cleaner.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&#39;re using FlowFuse, you don’t even need to write JavaScript yourself. You can simply ask the &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert&lt;/a&gt; in plain English, paste what your device manual says, and it will generate the Function node directly on your Node-RED canvas.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For standard Modbus registers, serial sensor protocols, and fixed-structure PLC memory layouts - which covers most industrial data, Buffer Parser does exactly what you need.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Binary data from industrial devices isn’t going anywhere. Modbus isn’t disappearing. Neither are PLCs from the 90s or sensors that still speak in raw bytes. This is the reality of factory floors, and it will be for a long time.&lt;/p&gt;
&lt;p&gt;The Buffer Parser makes that reality manageable. You don&#39;t need to be a buffer expert or master bitwise operations. You just need your device manual, a few minutes to configure the node, and—occasionally—the patience to flip the endianness when a value looks strange. The buffers are still just arrays of bytes, but now you have a tool that turns them into meaningful data without rewriting JavaScript every time you add a new sensor. That&#39;s worth something.&lt;/p&gt;
&lt;p&gt;And if you’re managing industrial devices at scale—handling remote Node-RED instances, deploying updates across fleets of edge hardware, or keeping everything secure and consistent—FlowFuse can remove much of the daily friction. With features like remote deployment, snapshots, secure device connectivity, and the FlowFuse AI Expert built right into the editor, you can &lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a free demo&lt;/a&gt;&lt;/strong&gt;. Our team will understand your requirements, show you exactly how FlowFuse fits into your workflow, and guide you on getting the most out of your industrial data pipelines.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/</id>
        <title>Building a Weather Dashboard in Node-RED (2026)</title>
        <summary>Build a live weather dashboard in Node-RED with FlowFuse</summary>
        <updated>2025-12-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A weather dashboard is honestly the best first project if you&#39;re getting into Node-RED. Takes about 10-15 minutes from start to finish, and by the end you&#39;ll understand how the whole thing works - connecting to APIs, processing data, and displaying it visually.&lt;/p&gt;
&lt;p&gt;This isn&#39;t one of our typical deep-dive industrial posts—it&#39;s a straightforward starter tutorial. You&#39;ll be building something real: calling an actual weather API, handling JSON responses, and watching live data appear on your dashboard. It&#39;s the kind of project that makes Node-RED&#39;s flow-based approach suddenly make sense. Once you&#39;ve built it, you&#39;ll have a solid foundation for more complex projects.&lt;/p&gt;
&lt;p&gt;We&#39;ll use FlowFuse Dashboard for the UI since it&#39;s modern and easier to work with. If you know how to drag nodes around and hit the deploy button, you&#39;re ready to start.&lt;/p&gt;
&lt;h2 id=&quot;what-you&#39;ll-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#what-you&#39;ll-need&quot;&gt;What You&#39;ll Need&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Instance:&lt;/strong&gt; You need Node-RED running somewhere. Easiest option is FlowFuse, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;grab a free trial&lt;/a&gt; and you get a cloud-hosted instance ready to go. No server setup, no port forwarding hassles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenWeatherMap Account:&lt;/strong&gt; Sign up at &lt;code&gt;openweathermap.org&lt;/code&gt;. The free tier gives you enough API calls for this project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;installing-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#installing-flowfuse-dashboard&quot;&gt;Installing FlowFuse Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, get the dashboard package installed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the hamburger menu in the top right corner&lt;/li&gt;
&lt;li&gt;Select Manage palette&lt;/li&gt;
&lt;li&gt;Go to the Install tab&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; in the search box&lt;/li&gt;
&lt;li&gt;Click the install button next to it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Wait for it to finish. You&#39;ll see a bunch of new dashboard nodes pop up in your left sidebar, things like &lt;strong&gt;ui-gauge&lt;/strong&gt;, &lt;strong&gt;ui-text&lt;/strong&gt;, &lt;strong&gt;ui-chart&lt;/strong&gt;. That&#39;s how you know it worked.&lt;/p&gt;
&lt;h2 id=&quot;getting-your-api-key&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#getting-your-api-key&quot;&gt;Getting Your API Key&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Log in to your OpenWeather account. Once you&#39;re signed in:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to your account section&lt;/li&gt;
&lt;li&gt;Find API keys&lt;/li&gt;
&lt;li&gt;Copy the default key (or generate a new one)&lt;/li&gt;
&lt;li&gt;Save it in a text file or a note app.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;setting-up-the-api-connection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#setting-up-the-api-connection&quot;&gt;Setting Up the API Connection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, we need to connect to the weather API and make sure it&#39;s working.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double-click to configure it&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Repeat&lt;/strong&gt; from &amp;quot;none&amp;quot; to &amp;quot;interval&amp;quot;&lt;/li&gt;
&lt;li&gt;Set it to repeat every 5 seconds (or whatever interval you prefer)&lt;/li&gt;
&lt;li&gt;Check the box for &lt;strong&gt;Inject once after&lt;/strong&gt; and set it to 0.1 seconds, this will trigger the flow immediately when you deploy&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Inject node configured to trigger the weather API every 5 seconds&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/trigger-weather-api.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Inject node configured to trigger the weather API every 5 seconds&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Drag an &lt;strong&gt;http request&lt;/strong&gt; node to the right of it&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;debug&lt;/strong&gt; node to the right of the &lt;strong&gt;http request&lt;/strong&gt; node&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;http request&lt;/strong&gt; node to open its settings:&lt;/li&gt;
&lt;li&gt;Make sure &lt;strong&gt;Method&lt;/strong&gt; is set to GET&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;URL&lt;/strong&gt; field, paste: &lt;code&gt;https://api.openweathermap.org/data/2.5/weather?q=London&amp;amp;appid=YOUR_API_KEY&amp;amp;units=metric&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;YOUR_API_KEY&lt;/code&gt; with the actual API key you copied from OpenWeatherMap&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;London&lt;/code&gt; with your city if you want&lt;/li&gt;
&lt;li&gt;Select the Return as &lt;strong&gt;parsed JSON&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;HTTP request node configured to fetch weather data from OpenWeatherMap API&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/http-request.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;HTTP request node configured to fetch weather data from OpenWeatherMap API&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;14&quot;&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;units=metric&lt;/code&gt; gives you Celsius. Change it to &lt;code&gt;units=imperial&lt;/code&gt; for Fahrenheit. For more details on what parameters you can use, check out the &lt;a href=&quot;https://openweathermap.org/current&quot;&gt;OpenWeatherMap API documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now wire the nodes together by clicking and dragging from the &lt;strong&gt;inject&lt;/strong&gt; node&#39;s right side to the &lt;strong&gt;http request&lt;/strong&gt; node&#39;s left side, then from the &lt;strong&gt;http request&lt;/strong&gt; node to the &lt;strong&gt;debug&lt;/strong&gt; node.&lt;/p&gt;
&lt;p&gt;Click the &lt;strong&gt;Deploy&lt;/strong&gt; button in the top right and open the debug panel on the right sidebar if it&#39;s not already open.&lt;/p&gt;
&lt;p&gt;You should see a JSON object with weather data, temperature, humidity, wind speed, description, and more. This is the raw data coming back from the API.&lt;/p&gt;
&lt;p&gt;If you see a 401 error, your API key may still be activating. Wait 10–15 minutes and try again, or verify the key again in case it’s invalid or mistyped.&lt;/p&gt;
&lt;h2 id=&quot;processing-the-weather-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#processing-the-weather-data&quot;&gt;Processing the Weather Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;re getting data from the API, you need to extract the specific values you want to display. We&#39;ll use a &lt;strong&gt;function&lt;/strong&gt; node to pull out temperature, humidity, weather description, and wind speed.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node and add following code into it and connect it to the &lt;strong&gt;http request&lt;/strong&gt; node:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-212&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-212&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Extract the data we need&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; humidity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;humidity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; description &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;weather&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; windSpeed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;speed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; city &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create separate messages for each value&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; city&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;city&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; description&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; humidity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;humidity&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; windSpeed&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wind&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-212&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you&#39;re using FlowFuse, you don&#39;t need to write this JavaScript manually. You can use the FlowFuse Expert to generate the function code for you—just describe what you want the &lt;strong&gt;function&lt;/strong&gt; node to do. Check out the &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;article&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Set the &lt;strong&gt;function&lt;/strong&gt; node&#39;s &lt;strong&gt;Outputs&lt;/strong&gt; (in the Setup tab) to 5, since the function will return five separate messages.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Function node configured with 5 outputs to split weather data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/function-setup-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Function node configured with 5 outputs to split weather data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This &lt;strong&gt;function&lt;/strong&gt; node splits the API response into separate outputs - one for temperature, one for humidity, and so on. Each output gets its own topic label so you can track what&#39;s what.&lt;/p&gt;
&lt;h2 id=&quot;building-the-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#building-the-dashboard&quot;&gt;Building the Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now you&#39;ll see your weather data displayed on screen. This demonstrates how Node-RED connects data sources to visual components. We&#39;ll organize the dashboard into separate groups for better visual organization.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-city-name-display&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#configuring-the-city-name-display&quot;&gt;Configuring the City Name Display&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start by displaying which city you&#39;re tracking:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-text&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect it to &lt;strong&gt;output 1&lt;/strong&gt; of your &lt;strong&gt;function&lt;/strong&gt; node (the city output)&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;ui-text&lt;/strong&gt; node to open its settings&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Label&lt;/strong&gt; to &amp;quot;City&amp;quot;&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Group&lt;/strong&gt;, click the pencil icon to create a new group called &amp;quot;Weather Info&amp;quot;&lt;/li&gt;
&lt;li&gt;Click Add, then Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI text node configured to display city name in Weather Info group&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/city-display.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;UI text node configured to display city name in Weather Info group&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You&#39;ve just created your first dashboard element and dashboard group. Groups organize widgets on the page and function as containers.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-weather-description&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#configuring-the-weather-description&quot;&gt;Configuring the Weather Description&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add a text field to show current conditions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;ui-text&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect it to &lt;strong&gt;output 2&lt;/strong&gt; of your &lt;strong&gt;function&lt;/strong&gt; node (description output)&lt;/li&gt;
&lt;li&gt;Double-click to configure&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Label&lt;/strong&gt; to &amp;quot;Conditions&amp;quot;&lt;/li&gt;
&lt;li&gt;Use the same &amp;quot;Weather Info&amp;quot; group&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI text node configured to display weather conditions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/condition-display.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;UI text node configured to display weather conditions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The API returns descriptions like &amp;quot;scattered clouds&amp;quot; or &amp;quot;light rain&amp;quot; - human-readable conditions.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-temperature-gauge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#configuring-the-temperature-gauge&quot;&gt;Configuring the Temperature Gauge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, add a circular gauge for temperature:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-gauge&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect it to &lt;strong&gt;output 3&lt;/strong&gt; of your &lt;strong&gt;function&lt;/strong&gt; node (the temperature output)&lt;/li&gt;
&lt;li&gt;Double-click to open settings&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Label&lt;/strong&gt; to &amp;quot;Temperature (°C)&amp;quot;&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Min&lt;/strong&gt; to 0 and &lt;strong&gt;Max&lt;/strong&gt; to 50 (adjust these based on your climate)&lt;/li&gt;
&lt;li&gt;Add the color segments you want, as shown in the reference image.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Group&lt;/strong&gt;, click the pencil icon to create a &lt;strong&gt;new group&lt;/strong&gt; called &amp;quot;Temperature &amp;amp; Humidity&amp;quot;&lt;/li&gt;
&lt;li&gt;Click Add to create the group&lt;/li&gt;
&lt;li&gt;Under the &lt;strong&gt;Appearance&lt;/strong&gt; tab, you can select a color scheme if desired&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Temperature gauge configured with color-coded segments in Temperature &amp;amp; Humidity group&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/temperature-gauge.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Temperature gauge configured with color-coded segments in Temperature &amp;amp; Humidity group&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The gauge will automatically color-code based on the value - cooler temperatures display in blue tones, warmer in orange/red.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-humidity-gauge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#configuring-the-humidity-gauge&quot;&gt;Configuring the Humidity Gauge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add the humidity gauge to the same group:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;ui-gauge&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect it to &lt;strong&gt;output 4&lt;/strong&gt; of your &lt;strong&gt;function&lt;/strong&gt; node (humidity output)&lt;/li&gt;
&lt;li&gt;Double-click to configure&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Label&lt;/strong&gt; to &amp;quot;Humidity (%)&amp;quot;&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Min&lt;/strong&gt; to 0 and &lt;strong&gt;Max&lt;/strong&gt; to 100 (humidity is always a percentage)&lt;/li&gt;
&lt;li&gt;Add the color segments you want, as shown in the reference image.&lt;/li&gt;
&lt;li&gt;Use the same &amp;quot;Temperature &amp;amp; Humidity&amp;quot; group from the dropdown&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Humidity gauge configured to display percentage values with color coding&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/humidity-gauge.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Humidity gauge configured to display percentage values with color coding&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The two gauges will display side by side in the same group, making it easy to compare both metrics at once.&lt;/p&gt;
&lt;h2 id=&quot;configuring-the-wind-speed-display&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#configuring-the-wind-speed-display&quot;&gt;Configuring the Wind Speed Display&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next, create a dedicated chart to display wind speed trends over time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-chart&lt;/strong&gt; node onto your flow.&lt;/li&gt;
&lt;li&gt;Connect it to &lt;strong&gt;output 5&lt;/strong&gt; of your &lt;strong&gt;function&lt;/strong&gt; node (the wind speed output).&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;ui-chart&lt;/strong&gt; node to configure it.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Label&lt;/strong&gt; to &lt;strong&gt;&amp;quot;Wind Speed (m/s)&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Type&lt;/strong&gt; to &lt;strong&gt;Line chart&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;X-axis&lt;/strong&gt;, select &lt;strong&gt;Timestamp&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Y-axis&lt;/strong&gt; to use &lt;strong&gt;msg.payload&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Series&lt;/strong&gt; to &lt;strong&gt;msg.topic&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Group&lt;/strong&gt;, click the pencil icon and create a &lt;strong&gt;new group&lt;/strong&gt; named &lt;strong&gt;&amp;quot;Wind Speed&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;, then &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Wind speed chart configured as a line chart to show trends over time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/wind-speed-chart.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Wind speed chart configured as a line chart to show trends over time&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;viewing-your-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#viewing-your-dashboard&quot;&gt;Viewing Your Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hit the Deploy button in the top right corner.&lt;/p&gt;
&lt;p&gt;Then, open the Dashboard 2.0 sidebar and click the Open Dashboard button. You should now see a dashboard similar to the one shown below.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Complete weather dashboard displaying real-time weather data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/weather-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Complete weather dashboard displaying real-time weather data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is the complete flow. Import it, enter your API URL with your API key in the &lt;strong&gt;http request&lt;/strong&gt; node, and deploy the flow:&lt;/p&gt;
&lt;div id=&quot;nr-flow-252&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow252 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;f4c08591654c29ef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger Weather API&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:100,&#92;&quot;y&#92;&quot;:1300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;70d3dab532802c97&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;70d3dab532802c97&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OpenWeather Request&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:1300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;849a9025bb2f8a78&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;849a9025bb2f8a78&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Process Weather Data&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Extract the data we need&#92;&#92;nconst temp = msg.payload.main.temp;&#92;&#92;nconst humidity = msg.payload.main.humidity;&#92;&#92;nconst description = msg.payload.weather[0].description;&#92;&#92;nconst windSpeed = msg.payload.wind.speed;&#92;&#92;nconst city = msg.payload.name;&#92;&#92;n&#92;&#92;n// Create separate messages for each value&#92;&#92;nreturn [&#92;&#92;n    { payload: city, topic: &#92;&#92;&#92;&quot;city&#92;&#92;&#92;&quot; },&#92;&#92;n    { payload: description, topic: &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot; },&#92;&#92;n    { payload: temp, topic: &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot; },&#92;&#92;n    { payload: humidity, topic: &#92;&#92;&#92;&quot;humidity&#92;&#92;&#92;&quot; },&#92;&#92;n    { payload: windSpeed, topic: &#92;&#92;&#92;&quot;wind&#92;&#92;&#92;&quot; },&#92;&#92;n];&#92;&quot;,&#92;&quot;outputs&#92;&quot;:5,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:1300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b32ec3dc036c981e&#92;&quot;],[&#92;&quot;d6a1cfaa374bf3e9&#92;&quot;],[&#92;&quot;5313d0217f55e2cf&#92;&quot;],[&#92;&quot;fca37c757fb4d69d&#92;&quot;],[&#92;&quot;b668bf185e686847&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5313d0217f55e2cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9470e51a8ec86d8e&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;alwaysShowTitle&#92;&quot;:false,&#92;&quot;floatingTitlePosition&#92;&quot;:&#92;&quot;top-left&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;°C&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#008cb4&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;15&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#00a3d7&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;25&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#fec700&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;35&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffaa00&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ff6251&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:1300,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b32ec3dc036c981e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;City Display&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;City:&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Arial,Arial,Helvetica,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;21&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:1220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d6a1cfaa374bf3e9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Conditions Display&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Conditions:&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Arial,Arial,Helvetica,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;21&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:1260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fca37c757fb4d69d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Humidity Gauge&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9470e51a8ec86d8e&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;value&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Humidity&#92;&quot;,&#92;&quot;alwaysShowTitle&#92;&quot;:false,&#92;&quot;floatingTitlePosition&#92;&quot;:&#92;&quot;top-left&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;%&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#d95000&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#6f7608&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;80&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#fec700&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#d95000&#92;&quot;,&#92;&quot;text&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textType&#92;&quot;:&#92;&quot;value&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:1340,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b668bf185e686847&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;7b2025c104cd506e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Wind Speed&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Wind Speed (m/s)&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;timestamp&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;xmin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xmax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;yAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bins&#92;&quot;:10,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#a347e1&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;interpolation&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:1380,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9470e51a8ec86d8e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temperature &amp;amp; Humidity&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;width&#92;&quot;:6,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Weather Info&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b2025c104cd506e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Wind Speed&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Weather Dashboard&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/weather&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;93822a7b43673c58&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;UI Name&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-notification&#92;&quot;],&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:5,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;93822a7b43673c58&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#00a3d7&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;950b3b399ea22ea6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.29.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow252.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-252&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s it! You&#39;ve built a real-time weather dashboard and learned the basics of Node-RED—connecting to APIs, processing data, and building visual interfaces.&lt;/p&gt;
&lt;p&gt;Throughout this tutorial, you used FlowFuse to host Node-RED and FlowFuse Dashboard for the UI. If you&#39;re just starting out, FlowFuse makes things easier—no server setup, no port forwarding, and your dashboard works anywhere. Plus, when you&#39;re ready to build bigger projects, features like team collaboration, DevOps pipelines, RBAC, snapshots, and audit logs are already built in.&lt;/p&gt;
&lt;p&gt;Try expanding your dashboard by adding more cities, creating historical charts, or setting up weather alerts. The pattern stays the same—you&#39;re just swapping data sources and visualizations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start your free FlowFuse trial&lt;/a&gt; and keep building.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/</id>
        <title>How to Access Optimized Data Blocks in TIA Portal (S7-1200/1500)</title>
        <summary>Use OPC UA to read optimized data blocks by name instead of fighting with memory addresses</summary>
        <updated>2025-12-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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/400 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;You can disable optimization in TIA Portal by unchecking the &amp;quot;Optimized block access&amp;quot; option in your data block properties. This gives you the old-style addressing where you can read data using fixed offsets like &lt;code&gt;DB1.DBW0&lt;/code&gt;. However, this approach has several drawbacks. Optimized blocks run faster, use less memory, and follow Siemens&#39; current best practices. If you&#39;re working on existing projects with thousands of tags, converting everything to standard blocks isn&#39;t practical. Many companies also require optimized blocks as part of their coding standards.&lt;/p&gt;
&lt;p&gt;This guide shows you how to read optimized data blocks directly without disabling optimization. You&#39;ll learn to use symbolic addressing, which is the proper way to access data from modern Siemens PLCs.&lt;/p&gt;
&lt;h2 id=&quot;why-reading-optimized-data-blocks-is-challenging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#why-reading-optimized-data-blocks-is-challenging&quot;&gt;Why Reading Optimized Data Blocks Is Challenging&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The S7 Protocol Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Traditional S7 communication, which most Node-RED S7 nodes use, relies on absolute memory addresses. You read data by specifying exact locations like &lt;code&gt;DB1,INT0&lt;/code&gt; (read integer at byte 0) or &lt;code&gt;DB5,REAL10&lt;/code&gt; (read real at byte 10).&lt;/p&gt;
&lt;p&gt;This worked fine with classic S7-300/400 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Optimization Breaks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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&#39;t at byte 4 anymore—it could be anywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why S7 Nodes Fail&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Node-RED packages like &lt;code&gt;node-red-contrib-s7&lt;/code&gt; need exact memory addresses. With optimized blocks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TIA Portal doesn&#39;t show you the actual memory layout&lt;/li&gt;
&lt;li&gt;Offsets can&#39;t be reliably determined&lt;/li&gt;
&lt;li&gt;Recompiling your PLC program silently breaks all your addresses&lt;/li&gt;
&lt;li&gt;The S7 protocol has no way to read variables by name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&#39;re stuck guessing at memory locations that keep changing.&lt;/p&gt;
&lt;h2 id=&quot;the-solution%3A-opc-ua&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#the-solution%3A-opc-ua&quot;&gt;The Solution: OPC UA&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA reads variables by name, not memory address. Instead of asking &amp;quot;what&#39;s at byte 10?&amp;quot; it asks &amp;quot;what&#39;s the value of Temperature_Sensor_01?&amp;quot;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;When you modify your data block or recompile, your flows keep working because they reference variable names, not memory locations that might shift.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you begin, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TIA Portal V13 or later, and you know how to download a program to your PLC&lt;/li&gt;
&lt;li&gt;A Siemens S7-1200 or S7-1500 PLC with OPC UA server support&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;FlowFuse Agent&lt;/a&gt; running on your edge device&lt;/li&gt;
&lt;li&gt;The PLC and edge device connected to the same network&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-1%3A-activate-opc-ua-server-on-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-1%3A-activate-opc-ua-server-on-your-plc&quot;&gt;Step 1: Activate OPC UA Server on Your PLC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, you need to activate the OPC UA server that&#39;s built into your S7-1200/1500 PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Launch TIA Portal and open your project&lt;/li&gt;
&lt;li&gt;In the project tree on the left, select your PLC and double-click it&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;OPC UA&lt;/strong&gt; in the device properties (usually under General or Properties section)&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Activate OPC UA Server&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Activate OPC UA server option in TIA Portal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/enable-opcua-server.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Activate OPC UA server option in TIA Portal&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Set &lt;strong&gt;Port&lt;/strong&gt; to &lt;code&gt;4840&lt;/code&gt; (the standard OPC UA port)&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Security Policy&lt;/strong&gt; to &lt;strong&gt;None&lt;/strong&gt; (for testing only)&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Guest authentication&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note that we&#39;ve disabled security entirely in steps 6-7 to get you up and running quickly. This is fine for learning and testing, but don&#39;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.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;step-2%3A-add-opc-ua-server-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-2%3A-add-opc-ua-server-interface&quot;&gt;Step 2: Add OPC UA Server Interface&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before exposing variables, you need to create an OPC UA server interface in your PLC configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For S7-1500 PLCs (firmware V2.5 or higher):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;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 &lt;strong&gt;Enable standard SIMATIC server interface&lt;/strong&gt; in the OPC UA settings. This automatically makes all PLC tags that are marked as accessible available through OPC UA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For S7-1200 PLCs (or manual configuration for S7-1500):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For S7-1200 PLCs, you must manually create a server interface and add the tags you want to expose:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In TIA Portal, navigate to &lt;strong&gt;OPC UA communication&lt;/strong&gt; in the project tree&lt;/li&gt;
&lt;li&gt;Right-click on &lt;strong&gt;Server interfaces&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Add new server interface&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding OPC UA server interface in TIA Portal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-server-interface.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding OPC UA server interface in TIA Portal&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Leave the default settings and click OK&lt;/li&gt;
&lt;li&gt;The server interface will be created (you can rename it if needed)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now this interface needs to know which data blocks to expose.&lt;/p&gt;
&lt;h2 id=&quot;step-3%3A-expose-your-data-block-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-3%3A-expose-your-data-block-variables&quot;&gt;Step 3: Expose Your Data Block Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For OPC UA to access your data blocks, you need to mark them as accessible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First, enable OPC UA access on your data blocks (required for all methods):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your data block in TIA Portal&lt;/li&gt;
&lt;li&gt;Right-click on the data block name in the project tree&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Properties&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Attributes&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Accessible from HMI/OPC UA&lt;/strong&gt; and &lt;strong&gt;Optimized Block Access&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Attribute settings for optimized and OPC UA accessible data blocks&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/optimized-db-and-accessbile-via-opcua-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Attribute settings for optimized and OPC UA accessible data blocks&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If using S7-1500 with standard SIMATIC server interface:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You&#39;re done. All variables in data blocks marked as accessible are now automatically available through OPC UA.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If using manual server interface (S7-1200 or S7-1500):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You need one more step to add specific variables to your server interface:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the project tree, expand &lt;strong&gt;OPC UA communication&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Expand your server interface&lt;/li&gt;
&lt;li&gt;Drag and drop variables from the &lt;strong&gt;OPC UA elements&lt;/strong&gt; panel (on the right) into your server interface table&lt;/li&gt;
&lt;li&gt;Alternatively, right-click &lt;strong&gt;Variables&lt;/strong&gt; and select &lt;strong&gt;Add new variable&lt;/strong&gt;, then browse to select them&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Tags added inside OPC UA server interface&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tags-added-in-the-server-interface.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Tags added inside OPC UA server interface&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compile and download:&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Compile&lt;/strong&gt; in TIA Portal&lt;/li&gt;
&lt;li&gt;Download the program to your PLC&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your OPC UA server is now running with the exposed variables ready for access.&lt;/p&gt;
&lt;h2 id=&quot;step-4%3A-install-opc-ua-client-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-4%3A-install-opc-ua-client-in-flowfuse&quot;&gt;Step 4: Install OPC UA Client in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now switch to your FlowFuse instance to set up the connection to your PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your FlowFuse editor&lt;/li&gt;
&lt;li&gt;Click the menu icon (three horizontal lines, top right)&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;In the search box, type &lt;code&gt;node-red-contrib-opcua&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Find the package in the results and click &lt;strong&gt;Install&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Confirm the installation when prompted&lt;/li&gt;
&lt;li&gt;Close the palette manager&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The OPC UA nodes will now appear in your node palette on the left side under the &amp;quot;opcua&amp;quot; category.&lt;/p&gt;
&lt;h2 id=&quot;step-5%3A-configure-opc-ua-connection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-5%3A-configure-opc-ua-connection&quot;&gt;Step 5: Configure OPC UA Connection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a new flow to connect to your PLC and read data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node onto your canvas&lt;/li&gt;
&lt;li&gt;Double-click it to open the configuration&lt;/li&gt;
&lt;li&gt;Click the pencil icon next to &lt;strong&gt;Endpoint&lt;/strong&gt; to add a new connection&lt;/li&gt;
&lt;li&gt;Enter the endpoint URL: &lt;code&gt;opc.tcp://[YOUR_PLC_IP]:4840&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;[YOUR_PLC_IP]&lt;/code&gt; with your actual PLC IP address (e.g., &lt;code&gt;opc.tcp://192.168.1.10:4840&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Security Policy&lt;/strong&gt; to &lt;strong&gt;None&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Security Mode&lt;/strong&gt; to &lt;strong&gt;None&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Authentication&lt;/strong&gt;, select &lt;strong&gt;Anonymous&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to save the endpoint&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to close the node configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your OPC UA client is now configured to connect to your PLC.&lt;/p&gt;
&lt;h2 id=&quot;step-6%3A-browse-available-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-6%3A-browse-available-variables&quot;&gt;Step 6: Browse Available Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now it&#39;s time to discover what&#39;s actually available on your PLC. Think of this like opening a file explorer to see what&#39;s inside.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto your canvas&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;OpcUa-Browser&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Connect the Inject node to the OpcUa-Browser node, then connect the OpcUa-Browser node to the Debug node&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;OpcUa-Browser&lt;/strong&gt; node to open its configuration&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Endpoint&lt;/strong&gt; dropdown, select the connection you created in Step 5&lt;/li&gt;
&lt;li&gt;Leave the &lt;strong&gt;Action&lt;/strong&gt; field set to &lt;strong&gt;browse&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; in the top-right corner&lt;/li&gt;
&lt;li&gt;Click the inject node button&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Debug&lt;/strong&gt; panel on the right side&lt;/li&gt;
&lt;li&gt;You&#39;ll see a structured tree showing everything your PLC is sharing&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-7%3A-read-your-first-variable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#step-7%3A-read-your-first-variable&quot;&gt;Step 7: Read Your First Variable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s prove this actually works by reading real data from your PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto your canvas&lt;/li&gt;
&lt;li&gt;Double-click the Inject node to configure it&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Repeat&lt;/strong&gt; from &amp;quot;none&amp;quot; to &lt;strong&gt;interval&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Set it to repeat &lt;strong&gt;every 5 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Topic&lt;/strong&gt; field, enter the NodeId you copied (e.g., &lt;code&gt;ns=3;s=&amp;quot;Demo_Datablock&amp;quot;.&amp;quot;Temperature&amp;quot;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double-click the OpcUa-Client node to open its configuration&lt;/li&gt;
&lt;li&gt;Select your endpoint from the &lt;strong&gt;Endpoint&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Change &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;read&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Double-click the Debug node&lt;/li&gt;
&lt;li&gt;Change the output to &lt;strong&gt;complete msg object&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Connect the Inject node to the OpcUa-Client node, then connect the OpcUa-Client node to the Debug node&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Open the Debug panel on the right side&lt;/li&gt;
&lt;li&gt;You&#39;ll see messages appearing every 5 seconds with your variable&#39;s value in &lt;code&gt;msg.payload&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;scale-your-industrial-applications-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/12/read-s7-optimized-datablocks-flowfuse/#scale-your-industrial-applications-with-flowfuse&quot;&gt;Scale Your Industrial Applications with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;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&#39;s happening in your operation.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Whether you&#39;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.&lt;/p&gt;
&lt;p&gt;Ready to scale beyond a single PLC? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; to see how FlowFuse can transform your industrial operations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/</id>
        <title>How to Optimize Industrial Data Communication with Protocol Buffers</title>
        <summary>Cut network traffic by 60% with binary serialization—three nodes, one file, no complexity</summary>
        <updated>2025-11-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;You&#39;re generating terabytes of sensor data every day. Most of it is waste, I mean..&lt;/p&gt;
&lt;p&gt;Not the measurements—those are fine. It&#39;s the packaging. Text formats wrap every reading in field names, quotes, and brackets. You&#39;re moving more formatting characters than actual data across your network.&lt;/p&gt;
&lt;p&gt;Protocol Buffers eliminates this. It&#39;s binary serialization that transmits only what matters—no overhead, no bloat. This article shows you how to implement it and what happens when you stop paying to transmit garbage.&lt;/p&gt;
&lt;p&gt;Don&#39;t worry about complexity—in FlowFuse this is three nodes and one text file. No thousand lines of code. You&#39;ll define your data structure in 5-10 lines, drag some nodes into your flow, point them at that file, and you&#39;re done. FlowFuse handles the rest.&lt;/p&gt;
&lt;h2 id=&quot;what-you&#39;re-actually-transmitting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#what-you&#39;re-actually-transmitting&quot;&gt;What You&#39;re Actually Transmitting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your network doesn&#39;t have a data problem. It has a packaging problem.&lt;/p&gt;
&lt;p&gt;Right now, somewhere in your facility, a sensor just reported 74°C. Simple reading. Four pieces of information. But here&#39;s what actually transmitted:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-21&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-21&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;T-220&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;74&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1700580000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OK&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-21&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;See those field names? &lt;code&gt;sensor_id&lt;/code&gt;, &lt;code&gt;temperature&lt;/code&gt;, &lt;code&gt;unit&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;. You wrote them once when you defined your data model. Now you&#39;re transmitting them thousands of times per second. Every single message carries a complete description of itself.&lt;/p&gt;
&lt;p&gt;It&#39;s like receiving a package where the shipping label is bigger than what&#39;s inside.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here&#39;s what this costs you:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One sensor sending 109 bytes every 5 seconds is nothing. One thousand sensors doing the same thing creates 21.8 KB/second of continuous traffic. That&#39;s 1.88 GB per day. Except only about 650 MB are actual measurement—the rest is field names, quotes, and brackets you&#39;re paying to transmit, store, and process.&lt;/p&gt;
&lt;p&gt;Your edge device receives this message and fires up a JSON parser. It reads character by character, validates every quote matches, converts &amp;quot;74&amp;quot; from a string into a number, and builds a data structure. This happens millions of times per day in a mid-sized facility. The CPU isn&#39;t processing sensor data—it&#39;s processing text formatting.&lt;/p&gt;
&lt;p&gt;Your control loop needs that temperature reading in 50 milliseconds. But the network is congested because it&#39;s moving 3-4x more data than necessary. The parser is slow because it&#39;s converting strings. And suddenly your 50ms requirement becomes 200ms, and nobody can figure out why because &amp;quot;we have plenty of bandwidth.&amp;quot;&lt;/p&gt;
&lt;p&gt;Meanwhile, your cloud provider charges by the gigabyte. Every month, you pay to ingest 1.88 GB from this sensor array. About 1.2 GB of that is field names and formatting. You&#39;re literally paying to store the word &amp;quot;temperature&amp;quot; millions of times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The compression trap:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The obvious fix is GZIP. Compress everything, cut it in half, problem solved. Except now you&#39;re compressing garbage, then paying CPU cycles to decompress it, then parsing the same bloated JSON on the other end. You&#39;ve added latency and processing overhead to save bandwidth on data you shouldn&#39;t be sending in the first place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if you just didn&#39;t send it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Protocol Buffers doesn&#39;t compress your JSON. It replaces it. No field names in every message—they&#39;re defined once in a schema. No quotes or brackets—it&#39;s binary. No string-to-number conversions—numbers are already numbers.&lt;/p&gt;
&lt;p&gt;That 109-byte JSON message becomes 47 bytes with Protocol Buffers. Not compressed. Just stripped of everything that isn&#39;t data—a 60% reduction in size.&lt;/p&gt;
&lt;p&gt;The same sensor array that generated 1.88 GB per day now generates 750 MB. Your edge devices process messages in microseconds instead of milliseconds. Your control loops hit their timing requirements. And your cloud bill drops by 60%.&lt;/p&gt;
&lt;p&gt;This isn&#39;t theoretical. It&#39;s measurable, repeatable, and you can implement it in an afternoon.&lt;/p&gt;
&lt;h2 id=&quot;understanding-protocol-buffers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#understanding-protocol-buffers&quot;&gt;Understanding Protocol Buffers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we dive into implementation, let&#39;s understand what makes Protocol Buffers different.&lt;/p&gt;
&lt;p&gt;Protocol Buffers (protobuf) is a serialization format developed by Google. Unlike JSON, which describes data with every message, protobuf separates the schema from the data. You define your message structure once in a &lt;code&gt;.proto&lt;/code&gt; file:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-73&quot;&gt;
  &lt;pre class=&quot;language-protobuf&quot;&gt;&lt;code id=&quot;code-73&quot; class=&quot;language-protobuf&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;proto3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Temperature sensor reading&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TemperatureSensorReading&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; sensor_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt; temperature &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;int64&lt;/span&gt; timestamp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; status &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-73&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Those numbers (1, 2, 3, 4, 5) are field identifiers. When you encode a message, protobuf transmits only the field number and the value. No field names, no formatting characters, no whitespace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The binary difference:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON: &lt;code&gt;{&amp;quot;sensor_id&amp;quot;:&amp;quot;T-220&amp;quot;,&amp;quot;temperature&amp;quot;:74,...}&lt;/code&gt; (109 bytes)&lt;/li&gt;
&lt;li&gt;Protobuf: &lt;code&gt;[21,0,0,74,66,26,7,99,101,108,11...&lt;/code&gt; (47 bytes)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The receiver uses the same &lt;code&gt;.proto&lt;/code&gt; file to decode field 1 as sensor_id, field 2 as temperature, and so on. The schema exists once on each side—never in the message itself.&lt;/p&gt;
&lt;p&gt;Now let&#39;s implement this in FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;implementing-protocol-buffers-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#implementing-protocol-buffers-in-flowfuse&quot;&gt;Implementing Protocol Buffers in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll build a complete protobuf pipeline: define your data schema, encode sensor readings, transmit them, and decode on the receiving end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before you start, Make sure you have a FlowFuse instance running on your edge device. If you don&#39;t have an account yet, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;create one with our free trial&lt;/a&gt;. FlowFuse simplifies connecting devices and systems—transform, validate, contextualize, and visualize data while building industrial applications, all in a low-code environment. It includes enterprise features that accelerate management, development, deployment, and scaling with built-in security.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;preparing-your-protocol-buffers-schema&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#preparing-your-protocol-buffers-schema&quot;&gt;Preparing Your Protocol Buffers Schema&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s start by defining your data structure. This will be the foundation of your binary serialization. If you&#39;re using FlowFuse Device Agent to run your Node-RED instance, it&#39;s recommended to create this file inside the &lt;code&gt;/opt/flowfuse-device/&lt;/code&gt; directory for proper access and management.&lt;/p&gt;
&lt;p&gt;Create a file named &lt;code&gt;temperature-sensor.proto&lt;/code&gt; ( or you can give it any name you want ). Make sure it ends with the &lt;code&gt;.proto&lt;/code&gt; extension:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-118&quot;&gt;
  &lt;pre class=&quot;language-protobuf&quot;&gt;&lt;code id=&quot;code-118&quot; class=&quot;language-protobuf&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;proto3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TemperatureSensorReading&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; sensor_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt; temperature &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;int64&lt;/span&gt; timestamp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; status &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-118&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can define as many message types as you need for different data in the file. Each message type gets its own structure optimized for the specific data it carries.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-protocol-buffers-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#installing-the-protocol-buffers-node&quot;&gt;Installing the Protocol Buffers Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To work with Protocol Buffers in FlowFuse, you&#39;ll need the protobuf node:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In your FlowFuse instance, open the palette manager (Menu → Manage palette)&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-protobuf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install the node&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed you will see the nodes in the left palette under the protobuf category.&lt;/p&gt;
&lt;h3 id=&quot;encoding-data-with-protocol-buffers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#encoding-data-with-protocol-buffers&quot;&gt;Encoding Data with Protocol Buffers&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag your data source node (Modbus Read, OPC UA Client, S7, etc.) into the flow. Ensure it&#39;s configured correctly and that data is coming through — you can verify this using a Debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transform the data as needed and add any required metadata.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;strong&gt;Encode&lt;/strong&gt; node to the flow. Open its configuration and click the &lt;strong&gt;+&lt;/strong&gt; icon next to &lt;strong&gt;Protofile&lt;/strong&gt; to add the full path to your &lt;code&gt;.proto&lt;/code&gt; file.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable &lt;strong&gt;Watch file&lt;/strong&gt; if you want the node to automatically reload when the &lt;code&gt;.proto&lt;/code&gt; changes&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Keep snake_case (underscores)&lt;/strong&gt; if your field names require it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Protocol Buffers node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/encode-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Protocol Buffers node configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Specify the &lt;strong&gt;Message Type&lt;/strong&gt; as defined in your &lt;code&gt;.proto&lt;/code&gt; file. For example, using the schema shown earlier, the type would be:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;TemperatureSensorReading
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells the Encode node which message structure to apply during serialization.&lt;/p&gt;
&lt;p&gt;If you need to set the type dynamically, you can also do:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-197&quot;&gt;
  &lt;pre class=&quot;language-js&quot;&gt;&lt;code id=&quot;code-197&quot; class=&quot;language-js&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;protobufType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TemperatureSensorReading&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-197&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Finally, connect the &lt;strong&gt;Encode&lt;/strong&gt; node to the communication node (or to the node that is transforming data and adding metadata) that will send your data onward, for example, MQTT Out, HTTP Request, or any other transport you&#39;re using.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once data passes through the Encode node, it will automatically encode it into Protocol Buffers. When everything is working correctly, you&#39;ll see the node status update to &amp;quot;processed&amp;quot; with a green indicator.&lt;/p&gt;
&lt;h3 id=&quot;decoding-protocol-buffers-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#decoding-protocol-buffers-data&quot;&gt;Decoding Protocol Buffers Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you&#39;re encoding and transmitting binary data, you need to decode it on the receiving end. This is where the matching &lt;code&gt;.proto&lt;/code&gt; schema comes into play.&lt;/p&gt;
&lt;p&gt;On your receiving FlowFuse instance (or wherever you&#39;re processing the data):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy the same &lt;code&gt;.proto&lt;/code&gt; file to your receiving system. The schema must match exactly—same field numbers, same types, same message structure. This is critical for successful decoding.&lt;/li&gt;
&lt;li&gt;Add the Decode node to your flow where you receive the protobuf data (after MQTT In, HTTP In, etc.)&lt;/li&gt;
&lt;li&gt;Configure the Decode node by Clicking the + icon next to Protofile and enter the full path to your &lt;code&gt;.proto&lt;/code&gt; file. Set the Message Type to match what was encoded (e.g., &lt;code&gt;TemperatureSensorReading&lt;/code&gt;). Enable Watch file if you want automatic reloading on schema changes.&lt;/li&gt;
&lt;li&gt;Connect Protocol buffer data source to Decode node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Decode node will parse the binary message and output a standard JavaScript object that you can work with in function nodes, store in databases, or display in dashboards.&lt;/p&gt;
&lt;h2 id=&quot;what-you-actually-get&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#what-you-actually-get&quot;&gt;What You Actually Get&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s talk about what changes when you actually implement this.&lt;/p&gt;
&lt;p&gt;Your network traffic drops by half or more. That struggling edge gateway suddenly has headroom. You can add more data sources or increase message frequency without upgrading anything.&lt;/p&gt;
&lt;p&gt;Your edge devices aren&#39;t parsing text anymore. Messages that took milliseconds now decode in microseconds. Those freed CPU cycles go back to your actual application logic. Your processing loops hit their timing requirements again.&lt;/p&gt;
&lt;p&gt;Your time-series database just got considerably smaller. The storage you already paid for goes further. That retention policy you&#39;ve been managing? You just extended it without buying anything.&lt;/p&gt;
&lt;p&gt;Your cloud provider charges per gigabyte. You were paying to transmit and store field names with every reading. Whatever your current cloud bill is, expect it to drop by 40-60%. Your provider doesn&#39;t care why—they just bill you for what moved through their infrastructure.&lt;/p&gt;
&lt;p&gt;Before Protocol Buffers, scaling meant budgeting for more capacity. After implementation, the same infrastructure handles more without additional spend. That next tier pricing? You just pushed it out by years.&lt;/p&gt;
&lt;p&gt;You&#39;re not rebuilding anything. Define a &lt;code&gt;.proto&lt;/code&gt; schema, drop in encode/decode nodes, deploy. No consultants, no multi-phase rollout, no capital purchases.&lt;/p&gt;
&lt;p&gt;This isn&#39;t optimization theater. It&#39;s removing waste that never should have been there. And once implemented, every new data source, every increased message rate, every additional field benefits from the same reduction. You&#39;re not just cutting your bill once—you&#39;re changing the cost structure of every future expansion.&lt;/p&gt;
&lt;h2 id=&quot;cut-the-waste-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/optimize-industrial-data-protocol-buffers/#cut-the-waste-now&quot;&gt;Cut the Waste Now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your messages are 60% packaging. Protocol Buffers strips it out.&lt;/p&gt;
&lt;p&gt;One schema file. Three nodes in FlowFuse. Deploy. Done.&lt;/p&gt;
&lt;p&gt;The same platform you use to connect devices, systems and build dashboards now optimizes every byte you transmit. No new tools. No complexity. Just smaller messages and lower bills.&lt;/p&gt;
&lt;p&gt;Pick one data flow. Implement it this afternoon. Scale it tomorrow.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start your free FlowFuse trial&lt;/a&gt; and stop paying to transmit field names.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/</id>
        <title>How to Protect Your Factory From Bad Data: A Must-Have Read for IIoT</title>
        <summary>How to validate industrial data before it enters your systems.</summary>
        <updated>2025-11-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Bad data quietly corrupts production analytics, triggers false equipment alarms, and causes automation systems to make faulty control decisions. Unlike system crashes, these issues go unnoticed until they&#39;ve already propagated through your operations—affecting multiple processes and causing unexpected shutdowns or production anomalies.&lt;/p&gt;
&lt;p&gt;This article shows you how to build a data validation gateway using FlowFuse that stops bad data before it reaches your critical systems. You&#39;ll implement validation checkpoints, establish quality rules, and configure alerts, creating a protective barrier that ensures only reliable data flows into your production environment.&lt;/p&gt;
&lt;p&gt;Below is a short video demonstration of the data validation gateway we&#39;ll be building together.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;_yThV3eurhw&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-problem-with-trusting-your-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#the-problem-with-trusting-your-data&quot;&gt;The Problem with Trusting Your Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most industrial applications assume incoming data is valid—temperature sensors send numbers between 0-100°C, MQTT messages contain properly formatted JSON, PLC status codes follow documented formats. There&#39;s usually no validation checking if these assumptions hold true.&lt;/p&gt;
&lt;p&gt;This works until it doesn&#39;t. Sensors drift out of calibration. Network issues corrupt packets. Firmware updates change data formats without warning. When these things happen, bad data flows straight through unchecked.&lt;/p&gt;
&lt;p&gt;Consider a temperature sensor sending &lt;code&gt;{&amp;quot;temperature&amp;quot;: 72.5, &amp;quot;unit&amp;quot;: &amp;quot;Celsius&amp;quot;}&lt;/code&gt;. Then electromagnetic interference corrupts transmission, and your system receives &lt;code&gt;{&amp;quot;temperature&amp;quot;: &amp;quot;ERR&amp;quot;, &amp;quot;unit&amp;quot;: &amp;quot;Celsius&amp;quot;}&lt;/code&gt;. Your code tries to do math with &amp;quot;ERR&amp;quot;—it fails silently, throws an exception, or worse, coerces &amp;quot;ERR&amp;quot; to NaN or 0. Now you&#39;re making decisions based on garbage data without realizing it.&lt;/p&gt;
&lt;p&gt;Scale makes this worse. With hundreds of sensors, multiple PLCs, edge gateways, and third-party integrations sending data continuously, quality issues aren&#39;t occasional—they&#39;re constant. You spend more time troubleshooting data problems than actual equipment problems. Reports contain incorrect numbers. Predictive models make bad predictions from corrupted training data.&lt;/p&gt;
&lt;p&gt;The solution isn&#39;t hoping for perfect data—it&#39;s validating it explicitly. That&#39;s what we&#39;re building in this guide.&lt;/p&gt;
&lt;h2 id=&quot;understanding-data-quality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#understanding-data-quality&quot;&gt;Understanding Data Quality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start building, we need to answer a simple but critical question:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What makes data &amp;quot;good&amp;quot;?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This isn&#39;t about what data you collect or which machine it comes from. It&#39;s about whether the data is &lt;strong&gt;reliable enough to drive decisions without causing chaos&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Good data enables confident automation and informed decision-making.&lt;/p&gt;
&lt;p&gt;Bad data misleads—and when your automation acts on misleading information, your team and operations pay the price.&lt;/p&gt;
&lt;p&gt;To build effective validation, you need to check multiple dimensions of data quality. Some key aspects include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type Correctness&lt;/strong&gt;: Is the temperature a number or the string &amp;quot;ERR&amp;quot;?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Completeness&lt;/strong&gt;: Are all required fields present?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Range Validation&lt;/strong&gt;: Is the temperature between 0-100°C or an impossible 500°C?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format Consistency&lt;/strong&gt;: Is the timestamp in ISO 8601 format or some custom format?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These aren&#39;t rigid categories—they&#39;re lenses through which you examine your data. Real validation often combines several of these checks together.&lt;/p&gt;
&lt;h2 id=&quot;building-your-data-quality-checker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#building-your-data-quality-checker&quot;&gt;Building Your Data Quality Checker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we understand what &amp;quot;good data&amp;quot; looks like, let&#39;s build guardrails to enforce it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before we start, make sure you have a running FlowFuse instance that is collecting data. If you don&#39;t have a real data source, don&#39;t worry—we&#39;ll provide a simulated setup as well. Just make sure you have a FlowFuse account and instance running. If you don&#39;t have an account, create one now with our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;installing-the-json-schema-validator-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#installing-the-json-schema-validator-node&quot;&gt;Installing the JSON Schema Validator Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For our validation system, we&#39;ll use &lt;a href=&quot;https://json-schema.org/&quot;&gt;JSON Schema&lt;/a&gt;, a powerful, industry-standard way to define what valid data should look like. Think of it as a contract that your data must fulfill before entering your system.&lt;/p&gt;
&lt;p&gt;JSON Schema lets you specify exactly what fields should exist, what types they should be, what ranges are acceptable, and what formats are required. Instead of writing dozens of if-statements to check each condition, you define the rules once in a schema, and the validator does the heavy lifting.&lt;/p&gt;
&lt;p&gt;To get started, install the &lt;code&gt;node-red-contrib-full-msg-json-schema-validation&lt;/code&gt; node in your FlowFuse instance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your FlowFuse instance&lt;/li&gt;
&lt;li&gt;Click the hamburger menu (three horizontal lines) in the top right&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-full-msg-json-schema-validation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; next to the node&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you&#39;ll find the &amp;quot;json full schema validator&amp;quot; node in your palette under the function category.&lt;/p&gt;
&lt;h3 id=&quot;creating-your-first-validation-schema&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#creating-your-first-validation-schema&quot;&gt;Creating Your First Validation Schema&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s start with a practical example—validating temperature sensor data. Here&#39;s what we expect our sensor to send:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-140&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-140&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEMP_LINE_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-140&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Now let&#39;s create a JSON Schema that validates this structure:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-144&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-144&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token property&quot;&gt;&quot;minimum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token property&quot;&gt;&quot;maximum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Temperature reading in Celsius&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token property&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Temperature unit (Celsius only)&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token property&quot;&gt;&quot;pattern&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^TEMP_LINE_[0-9]+$&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Sensor identifier following the required naming convention&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token property&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;date-time&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ISO 8601 formatted timestamp&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;additionalProperties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-144&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Let&#39;s break down what this schema validates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type Safety:&lt;/strong&gt; temperature must be a number (catches &lt;code&gt;&amp;quot;ERR&amp;quot;&lt;/code&gt;, null, undefined)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Required Fields:&lt;/strong&gt; all 4 must exist (catches incomplete messages)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Range Limits:&lt;/strong&gt; temperature must be between 0–100°C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value Constraints:&lt;/strong&gt; unit must match the enum &amp;quot;Celsius&amp;quot; (enforces consistent units)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format Rules:&lt;/strong&gt; ISO 8601 timestamps and &lt;code&gt;TEMP_LINE_*&lt;/code&gt; naming (catches config/naming errors)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;additionalProperties: false&lt;/code&gt; line is particularly important—it rejects any data with unexpected fields, preventing schema drift over time.&lt;/p&gt;
&lt;h4 id=&quot;building-the-validation-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#building-the-validation-flow&quot;&gt;Building the Validation Flow&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now let&#39;s build the flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag in your data input node such as MQTT In node, HTTP In node, or Inject node (for testing)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;JSON Full Schema Validator&lt;/strong&gt; node into your flow&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the validator node and paste your JSON schema into the schema field.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;JSON Schema Validator node configured with schema rules&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/json-schema-validator.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;JSON Schema Validator node configured with schema rules&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;The validator node has two outputs:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Output 1&lt;/strong&gt;: Valid data that passes all schema checks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output 2&lt;/strong&gt;: Invalid data that fails validation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When validation fails, the node adds a &lt;code&gt;msg.error&lt;/code&gt; property as an array, where each item provides detailed information about what went wrong (missing fields, incorrect types, out-of-range values, etc.)&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect Output 1 to your normal processing pipeline (database writes, dashboards, automation logic)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect Output 2 to an error handler that logs the error details.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;testing-your-validator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#testing-your-validator&quot;&gt;Testing Your Validator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Time to test your validator. We&#39;ll use the &lt;strong&gt;temperature sensor schema from the example above&lt;/strong&gt;, but you can follow these same steps with any schema you create. Just make sure your test payload matches what your schema expects—same field names, correct data types, and proper structure. Then you can tweak the values to trigger validation failures and see how your error handling responds.&lt;/p&gt;
&lt;p&gt;Add an &lt;strong&gt;Inject&lt;/strong&gt; node with this valid payload, and connect it to your JSON Schema Validator node:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-247&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-247&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEMP_LINE_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-247&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This passes all checks against the temperature sensor schema example and routes to your valid data handler.&lt;/p&gt;
&lt;p&gt;Now test with bad data:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-254&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-254&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ERR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEMP_LINE_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-254&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This fails because &lt;code&gt;temperature&lt;/code&gt; is a string instead of a number (as defined in our example schema), routing to your error handler. The &lt;code&gt;msg.error&lt;/code&gt; output shows exactly what&#39;s wrong:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-258&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-258&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;keyword&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;dataPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;schemaPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#/properties/temperature/type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;should be number&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-258&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;These detailed error messages eliminate guesswork. You see the field, the problem, and where validation failed.&lt;/p&gt;
&lt;p&gt;Test additional scenarios to see how the validator catches different issues:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Missing required field:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-268&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-268&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-268&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Out of range value:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-272&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-272&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEMP_LINE_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-272&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Invalid enum value:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-276&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-276&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;F&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEMP_LINE_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-11-21T10:30:00Z&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-276&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Each failure produces specific error messages that pinpoint the exact issue.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-error-alerts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#setting-up-error-alerts&quot;&gt;Setting Up Error Alerts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that your validator is catching bad data on Output 2, let&#39;s set up Telegram notifications so you get instant mobile alerts whenever validation fails.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-telegram-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#installing-the-telegram-node&quot;&gt;Installing the Telegram Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, install the Telegram node from the palette:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;hamburger menu&lt;/strong&gt; (three horizontal lines) in the top right.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-telegrambot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; next to the node.&lt;/li&gt;
&lt;li&gt;Wait for installation to complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you&#39;ll find the &amp;quot;telegram sender&amp;quot; and &amp;quot;telegram receiver&amp;quot; nodes in your palette.&lt;/p&gt;
&lt;h3 id=&quot;creating-your-telegram-bot-and-getting-your-chat-id&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#creating-your-telegram-bot-and-getting-your-chat-id&quot;&gt;Creating Your Telegram Bot and Getting Your Chat ID&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you can send alerts, you need to create a Telegram bot and get your Chat ID. We have a detailed guide that walks you through the entire process:  &lt;a href=&quot;https://flowfuse.com/node-red/notification/telegram/#creating-a-bot-in-telegram&quot;&gt;How to Create a Telegram Bot and Find Your Chat ID&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you have your &lt;strong&gt;bot token&lt;/strong&gt; and &lt;strong&gt;Chat ID&lt;/strong&gt;, come back here to continue with the alert setup.&lt;/p&gt;
&lt;h3 id=&quot;create-the-alert-message&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#create-the-alert-message&quot;&gt;Create the Alert Message&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll format the error information into a clear Telegram message.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find your validator node (the JSON Schema Validator).&lt;/li&gt;
&lt;li&gt;Look at its &lt;strong&gt;second output&lt;/strong&gt; (the bottom one). This is where bad data with errors comes out.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect it to the validator&#39;s &lt;strong&gt;second output&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Double-click the function node to open it.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;Name&lt;/strong&gt; at the top to: &lt;code&gt;Format Alert&lt;/code&gt; and add the following JavaScript:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-374&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-374&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Get error information&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; badData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Build error list&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; errorText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;errors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    errorText &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. Field: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataPath &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;unknown&#39;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#92;n&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    errorText &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;   Problem: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#92;n&#92;n&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Get current time&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Build the alert message&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;chatId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PUT_YOUR_CHAT_ID_HERE&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;🚨 DATA VALIDATION FAILED&lt;br /&gt;&lt;br /&gt;Time: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;time&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;Sensor: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;badData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sensor_id &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Unknown&#39;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;&lt;br /&gt;ERRORS FOUND:&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;errorText&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;&lt;br /&gt;BAD DATA:&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;badData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-374&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Find the line &lt;code&gt;chatId: &amp;quot;PUT_YOUR_CHAT_ID_HERE&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;PUT_YOUR_CHAT_ID_HERE&lt;/code&gt; with your actual Chat ID.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag &lt;strong&gt;telegram sender&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect your &lt;strong&gt;Format Alert&lt;/strong&gt; function node to the &lt;strong&gt;telegram sender&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;telegram sender&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; icon next to &lt;strong&gt;Bot&lt;/strong&gt; to add your bot configuration.&lt;/li&gt;
&lt;li&gt;Paste your &lt;strong&gt;Bot Token&lt;/strong&gt; that you got from BotFather.&lt;/li&gt;
&lt;li&gt;Give it a name like &amp;quot;Quality Check Bot&amp;quot;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;, then &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now test your setup by triggering a validation failure. You should receive an instant Telegram message showing exactly what went wrong.&lt;/p&gt;
&lt;p&gt;Below is the complete flow that demonstrates the entire validation pipeline—from receiving sensor data to catching errors and sending Telegram alerts.&lt;/p&gt;
&lt;div id=&quot;nr-flow-251&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow251 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;9b9f55548911ac66&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Invalid Data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;ERR&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Celsius&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;TEMP_LINE_01&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;2025-11-21T10:30:00Z&#92;&#92;&#92;&quot;}&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;93c2895e93507e19&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ae110e07ad7685d7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Data&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;df3cea6a5e793d66&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Format Alert&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Get error information&#92;&#92;nconst errors = msg.error || [];&#92;&#92;nconst badData = msg.payload || {};&#92;&#92;n&#92;&#92;n// Build error list&#92;&#92;nlet errorText = &#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot;;&#92;&#92;nerrors.forEach((err, index) =&amp;gt; {&#92;&#92;n    errorText += `${index + 1}. Field: ${err.dataPath || &#39;unknown&#39;}&#92;&#92;&#92;&#92;n`;&#92;&#92;n    errorText += `   Problem: ${err.message}&#92;&#92;&#92;&#92;n&#92;&#92;&#92;&#92;n`;&#92;&#92;n});&#92;&#92;n&#92;&#92;n// Get current time&#92;&#92;nconst time = new Date().toLocaleString();&#92;&#92;n&#92;&#92;n// Build the alert message&#92;&#92;nmsg.payload = {&#92;&#92;n    chatId: &#92;&#92;&#92;&quot;PUT_YOUR_CHAT_ID_HERE&#92;&#92;&#92;&quot;,&#92;&#92;n    type: &#92;&#92;&#92;&quot;message&#92;&#92;&#92;&quot;,&#92;&#92;n    content: `🚨 DATA VALIDATION FAILED&#92;&#92;n&#92;&#92;nTime: ${time}&#92;&#92;nSensor: ${badData.sensor_id || &#39;Unknown&#39;}&#92;&#92;n&#92;&#92;nERRORS FOUND:&#92;&#92;n${errorText}&#92;&#92;n&#92;&#92;nBAD DATA:&#92;&#92;n${JSON.stringify(badData, null, 2)}`&#92;&#92;n};&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;73c2d99fc1d7025a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c97a4811cf6d94ec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Valid Data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;:72.5,&#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Celsius&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;TEMP_LINE_01&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;2025-11-21T10:30:00Z&#92;&#92;&#92;&quot;}&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:250,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;93c2895e93507e19&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b82034c189d13fd5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Data Simulation&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;93c2895e93507e19&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;json-full-schema-validator&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;{&#92;&#92;n    &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;object&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;required&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;],&#92;&#92;n            &#92;&#92;&#92;&quot;properties&#92;&#92;&#92;&quot;: {&#92;&#92;n        &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;: {&#92;&#92;n            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;,&#92;&#92;n                &#92;&#92;&#92;&quot;minimum&#92;&#92;&#92;&quot;: 0,&#92;&#92;n                    &#92;&#92;&#92;&quot;maximum&#92;&#92;&#92;&quot;: 100,&#92;&#92;n                        &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Temperature reading in Celsius&#92;&#92;&#92;&quot;&#92;&#92;n        },&#92;&#92;n        &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;: {&#92;&#92;n            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n                &#92;&#92;&#92;&quot;enum&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;Celsius&#92;&#92;&#92;&quot;],&#92;&#92;n                    &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Temperature unit (Celsius only)&#92;&#92;&#92;&quot;&#92;&#92;n        },&#92;&#92;n        &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;: {&#92;&#92;n            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n                &#92;&#92;&#92;&quot;pattern&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;^TEMP_LINE_[0-9]+$&#92;&#92;&#92;&quot;,&#92;&#92;n                    &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Sensor identifier following the required naming convention&#92;&#92;&#92;&quot;&#92;&#92;n        },&#92;&#92;n        &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;: {&#92;&#92;n            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n                &#92;&#92;&#92;&quot;format&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;date-time&#92;&#92;&#92;&quot;,&#92;&#92;n                    &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;ISO 8601 formatted timestamp&#92;&#92;&#92;&quot;&#92;&#92;n        }&#92;&#92;n    },&#92;&#92;n    &#92;&#92;&#92;&quot;additionalProperties&#92;&#92;&#92;&quot;: false&#92;&#92;n}&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ae110e07ad7685d7&#92;&quot;],[&#92;&quot;df3cea6a5e793d66&#92;&quot;,&#92;&quot;30dce9e4816b95a9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;73c2d99fc1d7025a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;telegram sender&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bot&#92;&quot;:&#92;&quot;c588ce99d237a64a&#92;&quot;,&#92;&quot;haserroroutput&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;30dce9e4816b95a9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d7101f3a4d45deed&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Error&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c588ce99d237a64a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;telegram bot&#92;&quot;,&#92;&quot;botname&#92;&quot;:&#92;&quot;Quality Check Bot&#92;&quot;,&#92;&quot;usernames&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;chatids&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;baseapiurl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;testenvironment&#92;&quot;:false,&#92;&quot;updatemode&#92;&quot;:&#92;&quot;polling&#92;&quot;,&#92;&quot;pollinterval&#92;&quot;:300,&#92;&quot;usesocks&#92;&quot;:false,&#92;&quot;sockshost&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;socksprotocol&#92;&quot;:&#92;&quot;socks5&#92;&quot;,&#92;&quot;socksport&#92;&quot;:6667,&#92;&quot;socksusername&#92;&quot;:&#92;&quot;anonymous&#92;&quot;,&#92;&quot;sockspassword&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bothost&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;botpath&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localbothost&#92;&quot;:&#92;&quot;0.0.0.0&#92;&quot;,&#92;&quot;localbotport&#92;&quot;:8443,&#92;&quot;publicbotport&#92;&quot;:8443,&#92;&quot;privatekey&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useselfsignedcertificate&#92;&quot;:false,&#92;&quot;sslterminated&#92;&quot;:false,&#92;&quot;verboselogging&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;e1abd01699c129df&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-full-msg-json-schema-validation&#92;&quot;:&#92;&quot;1.1.0&#92;&quot;,&#92;&quot;node-red-contrib-telegrambot&#92;&quot;:&#92;&quot;17.0.3&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow251.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-251&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/industrial-data-validation-guide/#wrapping-up&quot;&gt;Wrapping Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You now have a working validator that stops corrupted data before it reaches your dashboards and automation logic. Bad sensor readings, malformed payloads, missing fields—your system catches them all and sends you detailed Telegram alerts the moment validation fails.&lt;/p&gt;
&lt;p&gt;Pick one critical data source and deploy your validator there first. Watch how it performs, adjust your schema based on real patterns, then roll it out to additional sources. Apply this approach everywhere data enters your system—MQTT streams, API endpoints, PLC connections. You&#39;ll shift from constantly troubleshooting mysterious failures to preventing them entirely.&lt;/p&gt;
&lt;p&gt;Pay attention to your validation metrics. High failure rates from specific sensors signal equipment problems. Recurring error patterns reveal network issues or configuration drift. Your validator becomes an early warning system for operational problems.&lt;/p&gt;
&lt;p&gt;The validation patterns you build today make your automation trustworthy tomorrow.&lt;/p&gt;
&lt;p&gt;Want to discover how FlowFuse helps you collect, validate, enrich, and use machine data to reduce costs and improve operational efficiency, along with powerful enterprise features? &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; to get started.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/</id>
        <title>Store-and-Forward at the Edge: Buffering Production Data During Network Outages</title>
        <summary>Keep collecting data when your network goes down</summary>
        <updated>2025-11-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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&#39;t wait for the network to recover.&lt;/p&gt;
&lt;p&gt;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&#39;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&#39;t hold up under review.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Below is the demo video where I show how production data can be lost without buffering, and how buffering prevents that from happening.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;J1gDj6S-ijI&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-store-and-forward%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#what-is-store-and-forward%3F&quot;&gt;What is Store-and-Forward?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;pre class=&quot;mermaid&quot;&gt;flowchart TD&amp;#10;    Source[PLC / Sensor]&amp;#10;    Destination[Cloud / Broker / Server]&amp;#10;&amp;#10;    Source --&amp;gt; Start[Data Arrives at Edge]&amp;#10;    Start --&amp;gt; Save[Store in Local Buffer]&amp;#10;    Save --&amp;gt; Check{Network Available?}&amp;#10;&amp;#10;    Check --&amp;gt;|Connected| Send[Send Data]&amp;#10;    Send --&amp;gt; Destination&amp;#10;    Destination --&amp;gt; Clear[Remove Data from Buffer]&amp;#10;&amp;#10;    Check --&amp;gt;|Disconnected| Wait[Keep Data in Buffer]&amp;#10;    Wait --&amp;gt; Retry[Retry Until Network Restored]&amp;#10;    Retry --&amp;gt; Check&amp;#10;&amp;#10;    %% Styling (consistent theme)&amp;#10;    style Source fill:#3B82F6,color:#fff&amp;#10;    style Start fill:#3B82F6,color:#fff&amp;#10;    style Save fill:#818CF8,color:#fff&amp;#10;    style Check fill:#6366F1,color:#fff&amp;#10;    style Send fill:#60A5FA,color:#fff&amp;#10;    style Destination fill:#60A5FA,color:#fff&amp;#10;    style Clear fill:#93C5FD,color:#000&amp;#10;    style Wait fill:#A5B4FC,color:#fff&amp;#10;    style Retry fill:#BFDBFE,color:#000&amp;#10;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s build a store-and-forward system to protect your data during network outages.&lt;/p&gt;
&lt;p&gt;We&#39;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.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You&#39;ll need the following before implementing store-and-forward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Edge Device Running FlowFuse Agent&lt;/strong&gt;: A running FlowFuse instance deployed on your edge hardware or gateway device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;node-red-node-sqlite&lt;/strong&gt;: SQLite node for local data storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-ping&lt;/strong&gt;: Ping node for connectivity monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1%3A-set-up-data-collection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-1%3A-set-up-data-collection&quot;&gt;Step 1: Set Up Data Collection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;FlowFuse handles this through Node-RED&#39;s 5,000+ community nodes, which support virtually every industrial protocol and interface—Modbus, OPC UA, MQTT, Ethernet/IP, GPIO pins, serial connections, and more. You collect data from your sources, transform it into the format you need, and prepare it for buffering.&lt;/p&gt;
&lt;p&gt;For this guide, we&#39;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&#39;re using.&lt;/p&gt;
&lt;p&gt;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, &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-implement-sqlite-buffering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-2%3A-implement-sqlite-buffering&quot;&gt;Step 2: Implement SQLite Buffering&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;SQLite provides the persistent storage layer for your store-and-forward buffer. It&#39;s lightweight, requires no separate database server, and handles the write volumes typical of industrial data collection without issue.&lt;/p&gt;
&lt;p&gt;Follow these steps to set up your SQLite buffer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;sqlite&lt;/strong&gt; node from the palette onto your workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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 &lt;strong&gt;sqlite&lt;/strong&gt;, select &lt;strong&gt;Read-write-create&lt;/strong&gt; as the mode, and click &lt;strong&gt;Add&lt;/strong&gt; to save the configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;SQLite database configuration with read-write-create mode enabled&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sqlite-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;SQLite database configuration with read-write-create mode enabled&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Set the SQL Query mode to &lt;strong&gt;Fixed Statement&lt;/strong&gt;. In the SQL Query field, enter:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-106&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-106&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; data_buffer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; AUTOINCREMENT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    sent &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    payload &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    created_at &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strftime&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;%s&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;now&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-106&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The payload stores the serialized data as JSON. The &lt;code&gt;sent&lt;/code&gt; 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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect an &lt;strong&gt;Inject&lt;/strong&gt; node to &lt;strong&gt;Sqlite&lt;/strong&gt; node&lt;/li&gt;
&lt;li&gt;Deploy your flow and click the inject node button to create the table.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-store-incoming-data-in-buffer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-3%3A-store-incoming-data-in-buffer&quot;&gt;Step 3: Store Incoming Data in Buffer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With your SQLite buffer ready, implement the logic to write incoming PLC data to storage.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;JSON&lt;/strong&gt; node onto the canvas and connect it to your data input source.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open its configuration. Set the Action to &lt;code&gt;Always convert to JSON String&lt;/code&gt; and set the Property to &lt;code&gt;msg.payload&lt;/code&gt;, then click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;JSON node configured to stringify payload data for storage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/stringify-json.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;JSON node configured to stringify payload data for storage&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;JSON&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the &lt;strong&gt;Change&lt;/strong&gt; node to configure it. Add the following rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt; (JSONata expression)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rule 2&lt;/strong&gt;: Set &lt;code&gt;msg.params.$ts&lt;/code&gt; to &lt;code&gt;msg.timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rule 3&lt;/strong&gt;: Set &lt;code&gt;msg.params.$payload&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node rules for preparing SQLite insert parameters&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-params-step-3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node rules for preparing SQLite insert parameters&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;Sqlite&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Change&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to configure it. Select your existing &lt;strong&gt;Sqlite&lt;/strong&gt; database, set the SQL Query mode to &lt;code&gt;Prepared Statement&lt;/code&gt;, and in the SQL Query field, enter:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-195&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-195&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; data_buffer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$ts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; $payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-195&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration and deploy your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your buffer now accumulates all incoming data. Each data point is serialized to JSON, structured into parameters, and written to SQLite with &lt;code&gt;sent=0&lt;/code&gt; (not yet forwarded). The prepared statement approach prevents SQL injection issues and handles special characters correctly.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-monitor-network-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-4%3A-monitor-network-connectivity&quot;&gt;Step 4: Monitor Network Connectivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Follow these steps to implement connectivity monitoring:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Ping&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to configure it. Enter the IP address or hostname of your destination system in the Target field (e.g., &lt;code&gt;broker.flowfuse.cloud&lt;/code&gt;), select mode to &amp;quot;Automatic&amp;quot;, set &amp;quot;Ping every&amp;quot; to &lt;code&gt;30&lt;/code&gt; seconds (adjust based on your requirements), name it &amp;quot;Network Health Check&amp;quot;, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Ping node configured to monitor network connectivity every 30 seconds&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ping.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Ping node configured to monitor network connectivity every 30 seconds&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Ping&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the &lt;strong&gt;Switch&lt;/strong&gt; node to configure it. Set the Property to &lt;code&gt;msg.payload&lt;/code&gt;,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;add Rule 1 as &lt;code&gt;false&lt;/code&gt; (network is down),&lt;/li&gt;
&lt;li&gt;add Rule 2 as &lt;code&gt;otherwise&lt;/code&gt; (network is reachable).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Switch node routing messages based on network connectivity status&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/if-connected-to-internet.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Switch node routing messages based on network connectivity status&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The switch node routes messages based on ping results. When ping fails, &lt;code&gt;msg.payload&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;. Otherwise, the ping succeeded with a response time.&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag two &lt;strong&gt;change&lt;/strong&gt; 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).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the first change node to configure it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;flow.networkOnline&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; (boolean) ( make sure it is stored in the persistent storage )&lt;/li&gt;
&lt;li&gt;Name it &amp;quot;Set Network Offline&amp;quot;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node setting network offline flag in persistent storage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-network-offline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node setting network offline flag in persistent storage&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Double-click the second change node to configure it:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;flow.networkOnline&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; (boolean)&lt;/li&gt;
&lt;li&gt;Name it &amp;quot;Set Network Online&amp;quot;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node setting network online flag when connectivity is restored&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-network-online.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node setting network online flag when connectivity is restored&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;Drag another &lt;strong&gt;change&lt;/strong&gt; node onto the canvas and configure it:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;flow.flowError&lt;/code&gt; to &lt;strong&gt;false&lt;/strong&gt; (this resets the error state triggered in the &lt;a href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#handle-errors-and-disconnections&quot;&gt;Handle Errors and Disconnections&lt;/a&gt; section).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node resetting error state when network becomes available&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-error.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node resetting error state when network becomes available&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Link Out&lt;/strong&gt; node onto the canvas and connect it to the &amp;quot;Set Network Online&amp;quot; node. Name it &amp;quot;Trigger Forward&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your connectivity monitoring is now complete. When the network is available, the system will trigger the forwarding logic to send buffered data.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-build-the-forwarding-logic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-5%3A-build-the-forwarding-logic&quot;&gt;Step 5: Build the Forwarding Logic&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h4 id=&quot;retrieve-and-prepare-unsent-records&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#retrieve-and-prepare-unsent-records&quot;&gt;Retrieve and Prepare Unsent Records&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Link In&lt;/strong&gt; node onto the canvas and name it &amp;quot;Trigger Forward&amp;quot;. Link this to the &lt;strong&gt;Link Out&lt;/strong&gt; node from Step 4.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;SQLite&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Link In&lt;/strong&gt; node. Name it &amp;quot;Get Unsent Data&amp;quot; and configure it by selecting your database, setting SQL Query mode to &lt;strong&gt;Fixed statement&lt;/strong&gt;, and entering the following SQL:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-374&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-374&quot; class=&quot;language-sql&quot;&gt;   &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; data_buffer &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; sent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ASC&lt;/span&gt; &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-374&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node onto the canvas and connect it to the SQLite node. Configure it to split &lt;strong&gt;msg.payload&lt;/strong&gt; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Split&lt;/strong&gt; node. Name it &amp;quot;Prepare Forward Message&amp;quot; and add the following rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;msg.record_id&lt;/code&gt; to &lt;code&gt;msg.payload.id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rule 2&lt;/strong&gt;: Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.payload.payload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node extracting record ID and payload for forwarding&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/prepare-forward-msg.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node extracting record ID and payload for forwarding&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;JSON&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Change&lt;/strong&gt; node. Configure it by setting Action to &lt;strong&gt;Always Convert to JSON Object&lt;/strong&gt; and Property to &lt;code&gt;msg.payload&lt;/code&gt;, then click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;JSON node configured to parse stored JSON string back to object&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/parse-json.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;JSON node configured to parse stored JSON string back to object&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Link Out&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;JSON&lt;/strong&gt; node. Name it &amp;quot;Send to Destination&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your forwarding logic now retrieves unsent records, prepares them for transmission, and passes them to the next stage for sending.&lt;/p&gt;
&lt;h3 id=&quot;step-6%3A-send-data-and-handle-errors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#step-6%3A-send-data-and-handle-errors&quot;&gt;Step 6: Send Data and Handle Errors&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This step implements data transmission to your destination with comprehensive error handling and buffer management.&lt;/p&gt;
&lt;h4 id=&quot;send-data-to-destination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#send-data-to-destination&quot;&gt;Send Data to Destination&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Link In&lt;/strong&gt; node onto the canvas and link it to the &lt;strong&gt;Link Out&lt;/strong&gt; node from Step 5. Name it &amp;quot;Send to Destination&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Link In&lt;/strong&gt; node. Name it &amp;quot;Check Network Online&amp;quot;, set the Property to &lt;code&gt;flow.networkOnline&lt;/code&gt;, add a condition &lt;code&gt;is true&lt;/code&gt;, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Switch node verifying network connectivity before sending data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/is-network-online.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Switch node verifying network connectivity before sending data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag another &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and connect it to the first switch node&#39;s output. Name it &amp;quot;Check Flow Error&amp;quot;, set the Property to &lt;code&gt;flow.flowError&lt;/code&gt;, add a condition &lt;code&gt;is false&lt;/code&gt;, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Switch node checking for error-free state before transmission&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/if-no-error.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Switch node checking for error-free state before transmission&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the second switch node&#39;s output. Configure it to append the record ID into the payload for transmission confirmation:
&lt;ul&gt;
&lt;li&gt;Rule 1: Set &lt;code&gt;msg.record_id&lt;/code&gt; to &lt;code&gt;msg.payload.record_id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node preserving record ID for transmission confirmation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-record-id-to-payload.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node preserving record ID for transmission confirmation&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Project Out&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Change&lt;/strong&gt; node. Double-click the node to open its configuration. Select &amp;quot;Send to specified node&amp;quot; as the mode, then enter select target &amp;quot;broadcast message&amp;quot; and enter topic (for example: &lt;code&gt;acme_manufacturing/plant_01/floor_2/cell_a/machine_A12/measurements&lt;/code&gt;). Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; you can use any output node that suits your architecture instead of Project Out, such as &lt;strong&gt;MQTT Out&lt;/strong&gt; for publishing to MQTT brokers, &lt;strong&gt;HTTP Request&lt;/strong&gt; for sending data to REST APIs, &lt;strong&gt;Database&lt;/strong&gt; nodes for writing directly to databases or other protocol-specific nodes depending on your destination requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;mark-records-as-sent-and-clear-buffer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#mark-records-as-sent-and-clear-buffer&quot;&gt;Mark Records as Sent and Clear Buffer&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Project In&lt;/strong&gt; node onto the canvas, double-click the node to configure it with source set to &amp;quot;Listen for broadcast messages&amp;quot;, 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Project In&lt;/strong&gt; node. Name it &amp;quot;Prepare Record ID&amp;quot; and configure the following rules:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt; (JSONata expression: &lt;code&gt;{}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rule 2&lt;/strong&gt;: Set &lt;code&gt;msg.params.$record_id&lt;/code&gt; to &lt;code&gt;msg.record_id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node preparing parameters for marking record as sent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-params-step-5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node preparing parameters for marking record as sent&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;SQLite&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Change&lt;/strong&gt; node. Name it &amp;quot;Mark as Sent&amp;quot;, then double-click it to configure. Select your database, set SQL Query mode to &lt;strong&gt;Prepared Statement&lt;/strong&gt;, and enter the following SQL:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-556&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-556&quot; class=&quot;language-sql&quot;&gt;   &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; data_buffer &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; sent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $record_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-556&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;SQLite&lt;/strong&gt; node onto the canvas and connect it to the previous SQLite node. Name it &amp;quot;Delete Record&amp;quot;, then double-click it to configure. Select database, set SQL Query mode to &lt;strong&gt;Prepared Statement&lt;/strong&gt;, and enter the following SQL:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-569&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-569&quot; class=&quot;language-sql&quot;&gt;   &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; data_buffer&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $record_id&lt;br /&gt;   &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; sent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-569&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save and deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;handle-errors-and-disconnections&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#handle-errors-and-disconnections&quot;&gt;Handle Errors and Disconnections&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Catch&lt;/strong&gt; node onto the canvas. Configure it to catch errors from all nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Catch&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name it &amp;quot;Set Flow Error&amp;quot; and configure it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;flow.flowError&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; (boolean)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node setting error flag when transmission fails&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-flow-error-flag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node setting error flag when transmission fails&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Status&lt;/strong&gt; node onto the canvas and configure it to monitor the &lt;strong&gt;Project&lt;/strong&gt; node&#39;s status.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and connect it to the status node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name it &amp;quot;Check Disconnected&amp;quot;, set the Property to &lt;code&gt;msg.status.text&lt;/code&gt;, add a condition &lt;code&gt;==&lt;/code&gt; with value &lt;code&gt;disconnected&lt;/code&gt;, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Switch&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name it &amp;quot;Set Network Failure Flag&amp;quot; and configure it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;: Set &lt;code&gt;flow.networkOnline&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; (boolean)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save and deploy your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/store-and-forward-edge-data-buffering/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You now have a working store-and-forward system that protects your data during network failures.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The system you&#39;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.&lt;/p&gt;
&lt;p&gt;If you want to get the flow template that you can use directly and modify according to your needs, check out our &lt;a href=&quot;https://flowfuse.com/blueprints/getting-started/store-and-forward/&quot;&gt;latest blueprint&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/</id>
        <title>FlowFuse 2.24: FlowFuse Expert in the Node-RED Editor, Scheduled Updates, Simpler Edge Device Addition, Store and Forward Blueprint, and what&#39;s next!</title>
        <summary>FlowFuse 2.24: FlowFuse Expert in the Node-RED Editor, Scheduled Updates, Simpler Edge Device Addition, Store and Forward Blueprint, and what&#39;s next!</summary>
        <updated>2025-11-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release unlocks several new abilities for our users, speeding your development time, easing management of Node-RED instances, providing a smoother path to adding large numbers of devices, and more. Let&#39;s dig in.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#flowfuse-expert&quot;&gt;FlowFuse Expert&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of FlowFuse Expert UI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-expert-ui.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[FlowFuse Expert UI]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The FlowFuse Expert used to live only on flowfuse.com, where you could use an LLM trained on FlowFuse and Node-RED documentation, and trained by the Node-RED experts at FlowFuse. Now, we&#39;ve taken it a step further. The FlowFuse Expert is now available inside of the FlowFuse UI, and even in the Immersive Editor in Node-RED!&lt;/p&gt;
&lt;p&gt;You are no longer limited in your interactions with the FlowFuse Expert by the location where you started your conversation. Keep the conversation going and rely on the Expert&#39;s advice right where you&#39;re building in Node-RED.&lt;/p&gt;
&lt;p&gt;Even better, when you&#39;re working in the Immersive Editor, the Expert will recommend flows based on your inputs, and you can copy and paste them directly into the Node-RED Editor, once again saving you time and reducing the effort needed to develop in Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;automatic-updates-of-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#automatic-updates-of-instances&quot;&gt;Automatic Updates of Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of Scheduled Updates UI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/scheduler.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Scheduled Updates Interface]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When there are new updates to Node-RED, or the FlowFuse components, it has been a manual task for users to spot the update and trigger the upgrade to get the latest fixes and features applied to their instances.&lt;/p&gt;
&lt;p&gt;We&#39;re here to make your tasks easier, not to give you more maintenance burdens. So with this release, we&#39;ve introduced the ability to automatically apply any updates that are available to Node-RED or the FlowFuse stack around it. You get to pick a maintenance window during the week for when the updates should get applied.&lt;/p&gt;
&lt;p&gt;For Starter tier teams, we will apply a default schedule for overnight at the weekend to minimise disruption. For Pro and Enterprise tiers, users can configure their own schedule via the Instance&#39;s Maintenance settings tab.&lt;/p&gt;
&lt;p&gt;Keeping your software up to date is important, and this features gives you one less thing to worry about.&lt;/p&gt;
&lt;h2 id=&quot;simpler-edge-device-addition&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#simpler-edge-device-addition&quot;&gt;Simpler Edge Device Addition&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of UI for provisioning token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/token.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Provisioning Token Interface]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Many of our customers make use of large fleets of edge devices. Through the use of provisioning tokens it&#39;s easy to get lots of devices setup quickly - but there were still some additional steps needed to get the devices properly named and organised. Now, when setting up a new device with a provisioning token, it is possible to name it at the same time, reducing the complexity of the workflow. We want you to be able to scale up your edge device count quickly and easily, and this represents a significant step in that direction.&lt;/p&gt;
&lt;h2 id=&quot;blueprint%3A-store-and-forward&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#blueprint%3A-store-and-forward&quot;&gt;Blueprint: Store and Forward&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When data acquisition and processing at the edge is mission critical, it is vital that data received at the edge can be stored and protected until it can be forwarded to its destination. Having heard from customers that an easy way to execute a store and forward structure is needed, we have created this Blueprint to speed your development of this data-preserving flow.&lt;/p&gt;
&lt;p&gt;Find out more on the &lt;a href=&quot;https://flowfuse.com/blueprints/getting-started/store-and-forward/&quot;&gt;blueprint page&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;sneak-peek&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#sneak-peek&quot;&gt;Sneak Peek&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;FlowFuse MCP nodes allow you to surface information to an LLM to create custom AI agents. We&#39;re working on enabling FlowFuse to identify anything you have surfaced to an MCP, paving the way for creating massively powerful agents, enabled by everything you&#39;ve connected to FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert-for-open-source-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#flowfuse-expert-for-open-source-node-red&quot;&gt;FlowFuse Expert for Open-Source Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Expert is our collection of AI-enhancements within the Node-RED editor - assisted creation of Function nodes, autocompleting flows and documentation generation amongst other features. Currently it&#39;s an exclusive feature of the FlowFuse platform, but we&#39;re hard at work to bring it to standalone Node-RED instances.&lt;/p&gt;
&lt;p&gt;Coming soon you&#39;ll be able to experience the power of AI-enhanced development within Node-RED wherever it&#39;s running.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.24 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.24.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse-release-2-24/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/</id>
        <title>Building a Web HMI for Factory Equipment Control</title>
        <summary>Create web-based operator interfaces for industrial equipment</summary>
        <updated>2025-11-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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&#39;re walking over there.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Here&#39;s what you&#39;ll build:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;NQZ_u25sy1Q&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before beginning, ensure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Edge device&lt;/strong&gt; - A computer, Raspberry Pi, or industrial PC that connects to your PLC and runs FlowFuse&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PLC on the same network&lt;/strong&gt; - Your PLC must be networked with your edge device&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Equipment to control&lt;/strong&gt; (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&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;understanding-the-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#understanding-the-setup&quot;&gt;Understanding the Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your PLC already controls your equipment. It reads sensors, executes logic, and switches outputs. That doesn&#39;t change.&lt;/p&gt;
&lt;p&gt;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/IP, S7, or whatever protocol your PLC speaks.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;hmi-design-principles-worth-knowing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#hmi-design-principles-worth-knowing&quot;&gt;HMI Design Principles Worth Knowing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into the build, it&#39;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.&lt;/p&gt;
&lt;p&gt;Good HMIs let operators quickly assess what&#39;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 &lt;a href=&quot;https://www.isa.org/standards-and-publications/isa-standards/isa-101-standards&quot;&gt;ISA-101&lt;/a&gt; ensures your color choices are consistent with what operators expect across different systems. We&#39;ll use this approach in our motor control example.&lt;/p&gt;
&lt;p&gt;Your PLC handles real-time control—your HMI just reflects what&#39;s happening. Polling intervals between 500-1000ms work well for most applications. Faster polling doesn&#39;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.&lt;/p&gt;
&lt;p&gt;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&#39;t reaching the equipment. Display connection status prominently, and consider disabling controls when disconnected.&lt;/p&gt;
&lt;h2 id=&quot;step-1%3A-set-up-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#step-1%3A-set-up-flowfuse&quot;&gt;Step 1: Set Up FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You need the FlowFuse agent running on an edge device that can reach your PLC over the network.&lt;/p&gt;
&lt;p&gt;Start by creating a &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;FlowFuse account&lt;/a&gt;. Once logged in, install and register the FlowFuse agent on your edge device by following this guide: &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;Installing Node-RED on Your Edge Device&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-2%3A-connect-to-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#step-2%3A-connect-to-your-plc&quot;&gt;Step 2: Connect to Your PLC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your HMI needs to talk to your PLC to read equipment status and send control commands. FlowFuse handles this through Node-RED&#39;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.&lt;/p&gt;
&lt;p&gt;Choose the node that matches your PLC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;node-red-contrib-modbus&lt;/a&gt;&lt;/strong&gt; – Modbus RTU/TCP PLCs and devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/&quot;&gt;node-red-contrib-s7&lt;/a&gt;&lt;/strong&gt; – Siemens S7-300/400/1200/1500&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;node-red-contrib-opcua&lt;/a&gt;&lt;/strong&gt; – OPC UA servers (universal industrial standard)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/&quot;&gt;node-red-contrib-cip-ethernet-ip&lt;/a&gt;&lt;/strong&gt; – Allen-Bradley/Rockwell PLCs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-mcprotocol&quot;&gt;node-red-contrib-mcprotocol&lt;/a&gt;&lt;/strong&gt; – Mitsubishi PLCs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-omron-fins&quot;&gt;node-red-contrib-omron-fins&lt;/a&gt;&lt;/strong&gt; – Omron PLCs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-bacnet&quot;&gt;node-red-contrib-bacnet&lt;/a&gt;&lt;/strong&gt; – BACnet building automation devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Installing Protocol Nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the hamburger menu (top right) → &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for your protocol node (e.g., &lt;code&gt;node-red-contrib-s7&lt;/code&gt; for Siemens).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Configuring Your Connection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Start with an input node for reading status (motor running, faults, sensor values). Use &lt;strong&gt;S7 In&lt;/strong&gt; for Siemens, &lt;strong&gt;Modbus Read&lt;/strong&gt; for Modbus devices, or &lt;strong&gt;OPC UA Client&lt;/strong&gt; for OPC UA servers, etc. Open the node configuration and click the pencil icon next to the &lt;strong&gt;Server/Connection&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;After saving the connection configuration, specify the &lt;strong&gt;variable addresses that provide the status information&lt;/strong&gt; you want to read (tags/registers such as motor state, faults, and sensor values). If available, enable efficiency features like &lt;strong&gt;“emit only on change”&lt;/strong&gt; or &lt;strong&gt;“subscribe mode”&lt;/strong&gt; to minimize unnecessary updates.&lt;/p&gt;
&lt;p&gt;For sending commands (start motor, stop motor, setpoints), drag the corresponding output node onto your canvas. When configuring it, select the &lt;strong&gt;same Server/Connection&lt;/strong&gt; 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/server 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; Some PLCs require configuration in their engineering software before allowing external access. For example, Siemens S7 requires &lt;strong&gt;PUT/GET communication&lt;/strong&gt; enabled in TIA Portal, and Allen-Bradley controllers may need &lt;strong&gt;explicit messaging&lt;/strong&gt; enabled in Studio 5000. Refer to your PLC’s documentation for any communication prerequisites.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test Your Connection:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node and connect it to your input node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Check for a green &amp;quot;connected&amp;quot; or &amp;quot;online&amp;quot; status indicator on your protocol node.&lt;/li&gt;
&lt;li&gt;Open the debug panel to verify data is flowing from your PLC.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you see live values in the debug panel, your PLC connection is working and you&#39;re ready to build the operator interface.&lt;/p&gt;
&lt;h2 id=&quot;step-3%3A-build-your-hmi-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#step-3%3A-build-your-hmi-dashboard&quot;&gt;Step 3: Build Your HMI Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With your PLC connected, let&#39;s create the operator interface using FlowFuse Dashboard, a set of UI nodes that build web-based interfaces without writing HTML or JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;install-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#install-dashboard-2.0&quot;&gt;Install Dashboard 2.0&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Click the hamburger menu and select &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;create-your-motor-control-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#create-your-motor-control-interface&quot;&gt;Create Your Motor Control Interface&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Add Control Buttons:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-button&lt;/strong&gt; widget onto your canvas.&lt;/li&gt;
&lt;li&gt;Double-click to open its configuration.&lt;/li&gt;
&lt;li&gt;Click the pencil icon next to &amp;quot;Group&amp;quot; to create a new group name, example, &amp;quot;Motor Controls&amp;quot; or another name that fits your equipment.&lt;/li&gt;
&lt;li&gt;Click the pencil icon next to &amp;quot;Page&amp;quot; to create a new page like &amp;quot;Line 1&amp;quot;, for example, &amp;quot;Line 1&amp;quot; or the area of your process this interface belongs to.&lt;/li&gt;
&lt;li&gt;Configure the button:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt;: &amp;quot;Start&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Payload&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt; (boolean)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background&lt;/strong&gt;: &lt;code&gt;#28A745&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Button node configuration showing Start label, true payload, and green background color&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/start-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Start button node configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Connect this node to your PLC write node.&lt;/li&gt;
&lt;li&gt;Repeat to add a &amp;quot;Stop&amp;quot; button with payload &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;#DC3545&lt;/code&gt; background.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Button node configuration showing Stop label, false payload, and red background color&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/stop-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Stop button node configuration&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;add-status-display&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#add-status-display&quot;&gt;Add Status Display&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The PLC continuously reports whether the motor is running or stopped as a boolean value. We&#39;ll convert these values into readable text with color-coded styling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Convert Boolean Values to Readable Status:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;switch&lt;/strong&gt; node onto the canvas and connect it to your PLC read node.&lt;/li&gt;
&lt;li&gt;Add two conditions: &lt;code&gt;is true&lt;/code&gt; and &lt;code&gt;is false&lt;/code&gt; to check &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Switch node configuration showing conditions for true and false values&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/switch-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Switch node configuration for motor status&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag two &lt;strong&gt;change&lt;/strong&gt; nodes onto the canvas:
&lt;ul&gt;
&lt;li&gt;Connect the first to the &amp;quot;true&amp;quot; output: set &lt;code&gt;msg.payload&lt;/code&gt; to &amp;quot;RUNNING&amp;quot; and &lt;code&gt;msg.class&lt;/code&gt; to &amp;quot;running&amp;quot;&lt;/li&gt;
&lt;li&gt;Connect the second to the &amp;quot;false&amp;quot; output: set &lt;code&gt;msg.payload&lt;/code&gt; to &amp;quot;STOPPED&amp;quot; and &lt;code&gt;msg.class&lt;/code&gt; to &amp;quot;stopped&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node configuration setting payload to RUNNING and class to running&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-running.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node configuration for running status&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node configuration setting payload to STOPPED and class to stopped&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-stopped.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node configuration for stopped status&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create the Status Display:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-text&lt;/strong&gt; widget onto your canvas.&lt;/li&gt;
&lt;li&gt;Double-click to configure:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Group&lt;/strong&gt;: Select &amp;quot;Motor Controls&amp;quot; (or create a &amp;quot;Status&amp;quot; group).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt;: Leave empty or enter &amp;quot;Motor Status:&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value Format&lt;/strong&gt;: &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Connect both change nodes to the ui-text widget.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI text widget configuration for displaying motor status&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/motor-status-text-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Motor status text widget configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add Status Styling:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-template&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Configure:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type&lt;/strong&gt;: Select &amp;quot;CSS (All Pages)&amp;quot; or &amp;quot;CSS (Single Page)&amp;quot;.&lt;/li&gt;
&lt;li&gt;Add this CSS:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-419&quot;&gt;
  &lt;pre class=&quot;language-css&quot;&gt;&lt;code id=&quot;code-419&quot; class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.running&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; lightgreen &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60px &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.stopped&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60px &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-419&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI template node with CSS styling for running and stopped status classes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/css.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;CSS template for status display styling&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and deploy the flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&#39;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 &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets.html&quot;&gt;widget reference&lt;/a&gt; for the full list.&lt;/p&gt;
&lt;h3 id=&quot;accessing-your-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#accessing-your-dashboard&quot;&gt;Accessing Your Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Local Network Access:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The dashboard in a remote instance isn&#39;t accessible by default. To enable it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Instance Settings&lt;/strong&gt; → &lt;strong&gt;Security&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;&amp;quot;Allow Offline Access&amp;quot;&lt;/strong&gt; and set a username and password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Instance security settings showing Allow Offline Access checkbox and authentication fields&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/enable-offline-access.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Enabling offline access in instance security settings&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;save settings&lt;/strong&gt;, then restart the instance using the top-right &lt;strong&gt;action&lt;/strong&gt; button dropdown&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;http://[device-IP]:1880/dashboard&lt;/code&gt; in your browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Web browser displaying the completed motor control HMI with start/stop buttons and status display&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-dashboard-hmi.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Completed HMI dashboard running in browser&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Remote Access:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enable MQTT in Your Team:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before you can use MQTT, you need to &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/&quot;&gt;enable the FlowFuse MQTT broker&lt;/a&gt; for your team, a one-time setup in your FlowFuse team settings that also covers PLC to MQTT integration in depth.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure Your Edge Device:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On your remote instance (the one connected to your PLC), you&#39;ll publish status data and subscribe to commands:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ff-mqtt-out&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click to open configuration and click &lt;strong&gt;&amp;quot;Configure access control&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;FlowFuse automatically creates an MQTT client for your instance—enable both &lt;strong&gt;Publish&lt;/strong&gt; and &lt;strong&gt;Subscribe&lt;/strong&gt; permissions.&lt;/li&gt;
&lt;li&gt;Set the topic to something descriptive like: &lt;code&gt;factory/line1/motor/status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Connect this node to your PLC read node (the one that gets motor status).&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;ff-mqtt-in&lt;/strong&gt; node and set its topic to: &lt;code&gt;factory/line1/motor/command&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Connect this node to your PLC write node (the one that controls the motor).&lt;/li&gt;
&lt;li&gt;Deploy your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your edge device now shares motor status via MQTT and listens for control commands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build Your Remote Dashboard:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a new &lt;a href=&quot;https://flowfuse.com/docs/user/introduction/#creating-a-node-red-instance&quot;&gt;hosted instance&lt;/a&gt; in FlowFuse. This instance runs in the cloud and will host your operator dashboard:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; using Manage Palette.&lt;/li&gt;
&lt;li&gt;Build your control interface following the same steps as before—add ui-button widgets for start/stop and ui-text widgets for status display.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;ff-mqtt-in&lt;/strong&gt; node with topic &lt;code&gt;factory/line1/motor/status&lt;/code&gt; and connect it to your status display widgets.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;ff-mqtt-out&lt;/strong&gt; node with topic &lt;code&gt;factory/line1/motor/command&lt;/code&gt; and connect it to your control buttons.&lt;/li&gt;
&lt;li&gt;Configure access control for this hosted instance&#39;s MQTT client (enable Publish and Subscribe).&lt;/li&gt;
&lt;li&gt;Deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your dashboard is now accessible at &lt;code&gt;https://[your-instance].flowfuse.cloud/dashboard&lt;/code&gt; 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.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;And if you need to deploy the solution across many production lines, FlowFuse&#39;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.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; 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.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/</id>
        <title>FlowFuse + LLM + MCP = Text Driven Operations</title>
        <summary>Moving from a Code driven interface to LLMs interpreting humans.</summary>
        <updated>2025-11-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;In industrial operations it&#39;s all about getting more out of the CAPEX already
spent. Achieving higher efficiency means everyone needs to get data from a lot of
different machines, have an understanding how these machines form lines and fit
together, and holistically understand these as a group of assets that collectively
can achieve more.&lt;/p&gt;
&lt;p&gt;With the rapid adoption of Artificial Intelligence (AI), Model Context
Protocol, low-code platforms it&#39;s clear that the future of operations is
conversational.
The interface to machines is becoming plain text, allowing teams to obtain effects
and scale operational excellence across entire business units simply by asking
the right questions.&lt;/p&gt;
&lt;h2 id=&quot;the-context-challenge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/#the-context-challenge&quot;&gt;The Context Challenge&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data capture involves integrating various machine protocols (like
&lt;a href=&quot;https://flowfuse.com/node-red/protocol/opc-ua/&quot;&gt;OPC-UA&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Modbus&lt;/a&gt;),
transporting, combining, and visualizing the information. While low-code tools
like Node-RED have decreased the implementation time to mere hours, the full
problem isn&#39;t solved: what happens &lt;em&gt;after&lt;/em&gt; the data is collected?&lt;/p&gt;
&lt;p&gt;Often, raw sensor data—like pressure, voltage, and temperature readings—lacks
context to immediately understand there&#39;s a problem worth solving. Even when a dashboard
has been built, spotting an issue (such as a high energy consumption on &lt;code&gt;machine 1&lt;/code&gt;)
doesn&#39;t inherently guide the operator on how to resolve it.
Furthermore, data flow often involves a psychological hurdle, moving from areas
where an engineer feels comfortable (perhaps the data storage side) to areas of
less expertise (like machine protocols or physical voltage readings).&lt;/p&gt;
&lt;p&gt;The goal is to asking high-level questions, such as:
&amp;quot;What changed in the energy consumption for machine 4?&amp;quot;.&lt;/p&gt;
&lt;h2 id=&quot;text%3A-the-new-language-of-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/#text%3A-the-new-language-of-control&quot;&gt;Text: The New Language of Control&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Removing code, often a complex layer, can be now achieved because of Large Language
Models (LLMs) and the Model Context Protocol (MCP).&lt;/p&gt;
&lt;p&gt;LLMs, like ChatGPT, predict the next word in a sentence, allowing humans to
query systems using &lt;strong&gt;natural language&lt;/strong&gt; rather than complex code.
LLMs face fundamental limitations though: they are typically cloud-based, can be
slow, and are trained at specific points in time, meaning they cannot inherently
react to real-time, event-based data or proprietary local context.&lt;/p&gt;
&lt;p&gt;This is where the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; steps in. The promise of
MCP is to give models more context through an agreed-upon protocol.
MCP allows operators to define exactly what read-only information (resources) or
functionality (tools) they want to expose to the LLM.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt; are read-only, like sensor readings, employee staff lists, vacation calendars, or specification sheets (e.g., upper and lower temperature limits).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt; are functions that allow the LLM to perform an action or change a state in the physical world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By feeding this context into an MCP server (such as the official &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mcp/&quot;&gt;FlowFuse MCP node&lt;/a&gt;),
the LLM transforms into a powerful operational partner.&lt;/p&gt;
&lt;p&gt;For example, an operator can ask: &amp;quot;Can you show me the last five temp sensor readings recorded?&amp;quot;.
Once the model identifies an anomaly, the operator can incorporate specifications and ask: &amp;quot;Are any of these values outside of spec for upper temp or lower temp?&amp;quot;.
If a problem is confirmed, the system can use staff and location data to answer a pointed question like: &lt;strong&gt;&amp;quot;Who are all the staff located nearest to the problem, and what is the quickest way to get there?&amp;quot;&lt;/strong&gt;.
This capability quickly transforms complex data into actionable steps—finding the problem, comparing it to specs, finding the right person, and routing them to the site—all within a matter of minutes.&lt;/p&gt;
&lt;h2 id=&quot;orchestrating-effects-across-the-machine-fleet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/#orchestrating-effects-across-the-machine-fleet&quot;&gt;Orchestrating Effects Across the Machine Fleet&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ability to propagate these text-driven decisions across many machines by the
same team is enabled by Node-RED serving as the essential integration layer.&lt;/p&gt;
&lt;p&gt;FlowFuse, a major corporate sponsor of Node-RED, aims to fuse the digital realm
with machines and the shop floor for IoT use cases. Node-RED acts as the shell
that connects proprietary and legacy machine protocols (OT side) to the modern MCP structure.&lt;/p&gt;
&lt;p&gt;If a manufacturing facility wants to allow an LLM to control a physical device,
Node-RED can integrate the machine (e.g., a Siemens S7 stack light) and wrap the
control logic in an MCP tool. The LLM requests an action
(e.g., &amp;quot;turn the stack light green&amp;quot;), the MCP tool sends the action through
Node-RED&#39;s established adapters, and the action is executed.&lt;/p&gt;
&lt;p&gt;This means that existing organizational logic and machine adapters, which have
already been integrated into Node-RED, can be instantly made LLM and AI ready.
This rapid adaptation allows a very broad spectrum of engineers to be applied to
problems, moving past relying on &amp;quot;tribal knowledge&amp;quot; held by a single expert.&lt;/p&gt;
&lt;h2 id=&quot;text-driven-playbooks-and-the-human-in-the-loop&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/flowfuse+llm+mcp-equals-text-driven-operations/#text-driven-playbooks-and-the-human-in-the-loop&quot;&gt;Text-Driven Playbooks and the Human in the Loop&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Looking ahead, this technology enables the creation of &lt;strong&gt;text-driven playbooks&lt;/strong&gt;.
An operator might input a natural language prompt:
&amp;quot;How do we optimize a certain procedure in the factory?&amp;quot;. The resulting
operational procedure, driven by the LLM and executed via MCP tools, becomes a
documented playbook. This system helps organizations achieve operational excellence
by turning human text input into processes that the rest of the company can read,
understand, and replicate.&lt;/p&gt;
&lt;p&gt;However, the industry must move cautiously. A critical element of the future of
operations is the necessity of a &lt;code&gt;human in the loop&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;AI is predictive and, in certain ways, random, meaning that if context slightly
changes, the output is not deterministic. When the consequences of an action are
physical or high-stakes
(e.g., stopping a production line, or an irreversible action like boiling an egg),
full control should not be handed over to a non-deterministic system. The risk of
an AI being &amp;quot;as confident when they&#39;re wrong as when they&#39;re right&amp;quot; necessitates human oversight.&lt;/p&gt;
&lt;p&gt;For the near future (the next five years), the AI acts as a partner or a fault
partner, making the uncomfortable aspects of complex flows more manageable. It is
currently best applied in reversible or digital tasks, such as generating reports
or triggering low-consequence actions like turning a stack light orange to signal
an engineer. As trust grows and impacts iterate, AI will gain more influence and
context, but the final, consequential decisions will remain with the human.&lt;/p&gt;
&lt;p&gt;The combination of LLMs, MCP, and Node-RED provides operators with super powers.
The operational floor is transforming from a place where experts write complex
code for singular machines, to a conversational environment where high-level, natural
language queries drive intelligent, scalable actions across the entire enterprise.&lt;/p&gt;
&lt;p&gt;Ready to experience text-driven operations in your own facility?
&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse for free&lt;/a&gt; or request a personalized demo to see how LLM-powered automation can transform your industrial processes.
&lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us today&lt;/a&gt; or sign up for our upcoming webinar to stay ahead in the Industry 4.0 revolution.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/</id>
        <title>Building a Label Scanner with FlowFuse for Product Labels &amp; Serial Numbers</title>
        <summary>A practical guide to automating text recognition in manufacturing workflows</summary>
        <updated>2025-11-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In production environments, labels are everywhere! Products have Serial Numbers and Lot Codes, Packages have Batch IDs and Dates. These are often critical to the processes for packaging, tracking, logging, inventory and so on.&lt;/p&gt;
&lt;p&gt;Many companies still do this manually. Someone types in each code as products move through the line. It&#39;s repetitive, time-consuming work - mistakes are inevitable.&lt;/p&gt;
&lt;p&gt;That&#39;s where OCR comes in. Optical Character Recognition (OCR) uses cameras to automatically read and extract text from labels and product markings. Instead of manual data entry, a camera simply captures the image and the system pulls out the information you need. It&#39;s a straightforward solution that&#39;s already being deployed in modern manufacturing facilities worldwide.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; width=&quot;400&quot; alt=&quot;Part with Serial No&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/serial-no-on-part.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Part with Serial No&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For example, take a look at the image above. When processed with OCR, it returns the following text:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Serial No: XYZ123456789
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tutorial shows you how you can build an OCR system using FlowFuse that can capture images from cameras, extract text from product labels, lot codes, and serial numbers, validate and parse the extracted data, store results in a database or trigger downstream workflows.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we dive in, make sure you have a running FlowFuse instance.
If you do not have one yet, you can &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;sign up for the 14-day free trial&lt;/a&gt; and get a hosted instance running in under two minutes.&lt;/p&gt;
&lt;h3 id=&quot;installing-required-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#installing-required-nodes&quot;&gt;Installing Required Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To perform text extraction from images, you’ll need to install the &lt;code&gt;@sumit_shinde_84/node-red-contrib-simple-ocr&lt;/code&gt; node in your FlowFuse instance.
This node uses the Tesseract OCR engine under the hood to recognize text from image files or image buffers.
To capture images and build a dashboard, you’ll also need the &lt;strong&gt;FlowFuse Dashboard&lt;/strong&gt; and &lt;strong&gt;Webcam&lt;/strong&gt; packages.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open your &lt;strong&gt;FlowFuse&lt;/strong&gt; editor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From the main menu, select &lt;strong&gt;Manage palette → Install&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Search for and install the following packages one by one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@sumit_shinde_84/node-red-contrib-simple-ocr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@sumit_shinde_84/node-red-dashboard-2-ui-webcam&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you’ll see the &lt;strong&gt;simple-ocr&lt;/strong&gt; node under the &lt;strong&gt;Function&lt;/strong&gt; category and the &lt;strong&gt;Webcam&lt;/strong&gt; widget under the &lt;strong&gt;dashboard 2.0&lt;/strong&gt; category in the left sidebar.&lt;/p&gt;
&lt;h3 id=&quot;building-the-scanner&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#building-the-scanner&quot;&gt;Building the Scanner&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let’s build a scanner dashboard that you can open on a mobile device, allowing the phone to act as a scanner for capturing product labels and serial numbers.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Label Scanner Built with FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-scanner.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Label Scanner Built with FlowFuse]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To capture images directly from your browser, you can use the &lt;strong&gt;FlowFuse Dashboard&lt;/strong&gt; along with the &lt;strong&gt;Webcam widget&lt;/strong&gt;, let&#39;s install them first.&lt;/p&gt;
&lt;h4 id=&quot;configuring-the-webcam-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#configuring-the-webcam-node&quot;&gt;Configuring the Webcam Node&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Webcam&lt;/strong&gt; widget onto your canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration.&lt;/li&gt;
&lt;li&gt;Create a new ui group for it to render the feed (for example, &lt;em&gt;OCR Scanner&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Button&lt;/strong&gt; widget onto the canvas and set its label to &lt;strong&gt;Scan&lt;/strong&gt;. Select the appropriate &lt;strong&gt;group&lt;/strong&gt;, check &lt;strong&gt;Enable pointerdown event&lt;/strong&gt;, and set the &lt;strong&gt;payload&lt;/strong&gt; to &lt;code&gt;&amp;quot;capture&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;. When the button is clicked, it will send the &lt;code&gt;&amp;quot;capture&amp;quot;&lt;/code&gt; payload, which will trigger the &lt;strong&gt;Webcam&lt;/strong&gt; widget to capture an image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Scan Label Button Widget Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/scan-label-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Scan Label Button Widget Configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Deploy the flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When deployed, this flow creates a dashboard interface with a live camera preview and a large Scan Label button. Each time you click Scan Label, the captured image is sent as a &lt;code&gt;msg.payload.image&lt;/code&gt; containing a image buffer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Tip: To correct a flipped or mirrored camera preview, open the three-dot menu (⋮) on the webcam widget and enable &amp;quot;Mirror Image&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id=&quot;handling-high-resolution-images&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#handling-high-resolution-images&quot;&gt;Handling High-Resolution Images&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;When capturing an image, if you encounter an error stating that the image size exceeds &lt;strong&gt;Dashboard 2.0’s&lt;/strong&gt; &lt;code&gt;maxHttpBufferSize&lt;/code&gt;, you’ll need to reduce the image resolution or quality — otherwise, the dashboard connection may reset.&lt;/p&gt;
&lt;p&gt;To fix this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Double-click the &lt;strong&gt;Webcam&lt;/strong&gt; widget.&lt;/li&gt;
&lt;li&gt;Adjust the &lt;strong&gt;image width&lt;/strong&gt;, &lt;strong&gt;height&lt;/strong&gt;, and &lt;strong&gt;quality&lt;/strong&gt; parameters.&lt;/li&gt;
&lt;li&gt;By default, these are set to &lt;strong&gt;640×480&lt;/strong&gt; resolution and &lt;strong&gt;0.8&lt;/strong&gt; quality.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also check the image size from the webcam output using &lt;code&gt;msg.payload.sizeBytes&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;adding-the-ocr-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#adding-the-ocr-node&quot;&gt;Adding the OCR Node&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now, let’s add an OCR node to extract text from the captured images.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.payload.image&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Simple OCR&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;Webcam&lt;/strong&gt; widget to the &lt;strong&gt;Change&lt;/strong&gt; node, and then connect the &lt;strong&gt;Change&lt;/strong&gt; node’s output to the &lt;strong&gt;Simple OCR&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node and connect it to the &lt;strong&gt;Simple OCR&lt;/strong&gt; node to view the results.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;, then &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next, open the dashboard by clicking the &lt;strong&gt;Dashboard 2.0&lt;/strong&gt; button in the right sidebar. Then, click the &lt;strong&gt;Scan Label&lt;/strong&gt; button — the first click will activate your camera (make sure to grant your browser permission to access it).&lt;/p&gt;
&lt;p&gt;Position the label in front of the camera, focus on it, and click &lt;strong&gt;Scan&lt;/strong&gt; again. The recognized text will appear in the &lt;strong&gt;Debug&lt;/strong&gt; panel.
Now, you need to validate and trim the recognized text, and add a visual indicator to show a successful scan. Let’s set that up next.&lt;/p&gt;
&lt;h4 id=&quot;validating-and-parsing-the-extracted-text&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#validating-and-parsing-the-extracted-text&quot;&gt;Validating and Parsing the Extracted Text&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The OCR node returns raw text that may contain extra whitespace, line breaks, or unwanted characters. Let&#39;s add validation and parsing logic:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;Function&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect it after the &lt;strong&gt;simple-ocr&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Add the following code:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-219&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-219&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Extract and clean OCR text&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[&#92;r&#92;n]+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39; &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^&#92;w&#92;s:]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&#92;s+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39; &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Match part number&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;(?:Part&#92;s*No|No)[:&#92;s]+([0-9A-Z]{6,12})&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; part &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; match&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Validate format: 6 digits + 2 letters + 2 digits&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; valid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; part &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^&#92;d{6}[A-Z]{2}&#92;d{2}$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;part&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Build payload&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; valid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;partNumber&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; valid &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; part &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;notificationMsg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; valid&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Label successfully scanned: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;part&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Scan failed — Invalid or unreadable label.&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-219&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: You don’t need to know JavaScript to create a function for validating and extracting the label text you’re scanning — just tell the &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert&lt;/a&gt; what you want, and it will generate it for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This function cleans the text, validates that something was detected, and attempts to extract structured data like serial numbers or part numbers using regular expressions.&lt;/p&gt;
&lt;h4 id=&quot;adding-visual-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#adding-visual-feedback&quot;&gt;Adding Visual Feedback&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Users need immediate feedback when a scan succeeds or fails. Let&#39;s add both visual indicators:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the validation Function node.&lt;/li&gt;
&lt;li&gt;Configure the Change node to set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.payload.notificationMsg&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-notification&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the ui-notification node to configure it:
&lt;ul&gt;
&lt;li&gt;Select or create a &lt;strong&gt;UI Base&lt;/strong&gt; configuration&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;position&lt;/strong&gt; to &lt;strong&gt;center&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Optionally, configure the &lt;strong&gt;timeout&lt;/strong&gt; duration (e.g., 3000ms for 3 seconds)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Connect the Change node output to the ui-notification node input.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and &lt;strong&gt;Deploy&lt;/strong&gt; the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now when you scan a label:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the scan is successful, you&#39;ll see a green notification with &amp;quot;Label successfully scanned: [part number]&amp;quot;&lt;/li&gt;
&lt;li&gt;If the scan fails, you&#39;ll see a warning notification with &amp;quot;Scan failed — Invalid or unreadable label&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your OCR scanning system is now complete! You can test it by opening the dashboard on your mobile device, positioning a product label in front of the camera, and clicking the Scan button. The system will capture the image, extract the text, validate it, and provide immediate visual feedback on the scan result.&lt;/p&gt;
&lt;div id=&quot;nr-flow-249&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow249 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;a21c3c47d1f1cf10&#92;&quot;,&#92;&quot;3a71e800415a3966&#92;&quot;,&#92;&quot;ce383856293fe7e8&#92;&quot;,&#92;&quot;8858da9d0167fa59&#92;&quot;,&#92;&quot;45093fdd9e8c7374&#92;&quot;,&#92;&quot;223bb060bd896be0&#92;&quot;,&#92;&quot;c4a91f5b52a9c469&#92;&quot;,&#92;&quot;020e11e740154489&#92;&quot;,&#92;&quot;6ad6bad695c34c7b&#92;&quot;,&#92;&quot;31d2eb3589e05d01&#92;&quot;],&#92;&quot;x&#92;&quot;:84,&#92;&quot;y&#92;&quot;:279,&#92;&quot;w&#92;&quot;:822,&#92;&quot;h&#92;&quot;:242},{&#92;&quot;id&#92;&quot;:&#92;&quot;a21c3c47d1f1cf10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;simple-ocr&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c4a91f5b52a9c469&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3a71e800415a3966&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-webcam&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;qrDetection&#92;&quot;:false,&#92;&quot;imageWidth&#92;&quot;:&#92;&quot;150&#92;&quot;,&#92;&quot;imageHeight&#92;&quot;:&#92;&quot;150&#92;&quot;,&#92;&quot;imageQuality&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;31d2eb3589e05d01&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ce383856293fe7e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Scan Label Button&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;SCAN&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:false,&#92;&quot;enablePointerdown&#92;&quot;:true,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;capture&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:false,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3a71e800415a3966&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8858da9d0167fa59&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Extract and Validate Part Number&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Extract and clean OCR text&#92;&#92;nlet text = (msg.payload.text || msg.payload || &#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot;)&#92;&#92;n  .replace(/[&#92;&#92;&#92;&#92;r&#92;&#92;&#92;&#92;n]+/g, &#39; &#39;)&#92;&#92;n  .replace(/[^&#92;&#92;&#92;&#92;w&#92;&#92;&#92;&#92;s:]/g, &#39;&#39;)&#92;&#92;n  .replace(/&#92;&#92;&#92;&#92;s+/g, &#39; &#39;)&#92;&#92;n  .trim();&#92;&#92;n&#92;&#92;n// Match part number&#92;&#92;nlet match = text.match(/(?:Part&#92;&#92;&#92;&#92;s*No|No)[:&#92;&#92;&#92;&#92;s]+([0-9A-Z]{6,12})/i);&#92;&#92;nlet part = match?.[1]?.trim() || null;&#92;&#92;n&#92;&#92;n// Validate format: 6 digits + 2 letters + 2 digits&#92;&#92;nlet valid = part ? /^&#92;&#92;&#92;&#92;d{6}[A-Z]{2}&#92;&#92;&#92;&#92;d{2}$/.test(part) : false;&#92;&#92;n&#92;&#92;n// Build payload&#92;&#92;nmsg.payload = {&#92;&#92;n  success: valid,&#92;&#92;n  partNumber: valid ? part : null,&#92;&#92;n  timestamp: new Date().toISOString(),&#92;&#92;n  notificationMsg: valid&#92;&#92;n    ? `✅ Label successfully scanned: ${part}`&#92;&#92;n    : &#92;&#92;&#92;&quot;⚠️ Scan failed — Invalid or unreadable label.&#92;&#92;&#92;&quot;&#92;&#92;n};&#92;&#92;n&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;223bb060bd896be0&#92;&quot;,&#92;&quot;6ad6bad695c34c7b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;45093fdd9e8c7374&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;allowConfirm&#92;&quot;:false,&#92;&quot;confirmText&#92;&quot;:&#92;&quot;Confirm&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;223bb060bd896be0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.notificationMsg&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;45093fdd9e8c7374&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4a91f5b52a9c469&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;020e11e740154489&#92;&quot;],&#92;&quot;x&#92;&quot;:865,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;020e11e740154489&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 1&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;c4a91f5b52a9c469&#92;&quot;],&#92;&quot;x&#92;&quot;:125,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8858da9d0167fa59&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6ad6bad695c34c7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:540,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;31d2eb3589e05d01&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;9cf82b68bb89e8ce&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;604f466d22e1157b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.image&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:560,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a21c3c47d1f1cf10&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5a89ac7171f51cc3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Scanner&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;width&#92;&quot;:6,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;UI Name&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-notification&#92;&quot;],&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:5,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;f1eb99b1e714d411&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Page Name&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;93822a7b43673c58&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;93822a7b43673c58&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#00a3d7&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5b8bfbe56c87605&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@sumit_shinde_84/node-red-contrib-simple-ocr&#92;&quot;:&#92;&quot;0.1.1&#92;&quot;,&#92;&quot;@sumit_shinde_84/node-red-dashboard-2-ui-webcam&#92;&quot;:&#92;&quot;1.1.2&#92;&quot;,&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.29.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow249.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-249&#39;) })&lt;/script&gt;
&lt;p&gt;If you want to fully automate this process, you can set up a fixed camera positioned where products pass through on the production line. This approach eliminates manual scanning, but it will require proper camera mounting, lighting setup, and trigger mechanisms to capture images at the right moment as products move past the camera.&lt;/p&gt;
&lt;p&gt;Furthermore, you can push scanned label data to a database. The easiest way to do this is using &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/&quot;&gt;FlowFuse Tables&lt;/a&gt;, which is a built-in database service managed by FlowFuse. You&#39;ll find the &lt;strong&gt;query&lt;/strong&gt; node in the palette that not only simplifies setup by connecting to the FlowFuse Tables database without any setup, it also has access to the integrated FlowFuse Expert, allowing you to &lt;a href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/&quot;&gt;generate queries using natural language&lt;/a&gt; — no SQL skills required!&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/building-label-scanner-with-flowfuse/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;ve just built a working OCR system that turns any mobile device into a label scanner. It captures images, reads text, validates the data, and gives instant feedback—all without writing hundreds of lines of code.&lt;/p&gt;
&lt;p&gt;This is just the starting point. Your system can grow with your needs: connect it to your inventory database, add support for different label formats, set up multiple scanning stations, or integrate it with your existing ERP system. The foundation is there.&lt;/p&gt;
&lt;p&gt;Also, this OCR scanner is just one piece of what&#39;s possible with FlowFuse. Imagine connecting all your manufacturing systems—machine data, quality checks, inventory tracking, production metrics—into a unified industrial data platform where everything flows together seamlessly.&lt;/p&gt;
&lt;p&gt;FlowFuse helps manufacturers like you break down data silos and build connected, intelligent operations. From shop floor to top floor, your data works together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;See it in action.&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; and discover how FlowFuse can transform your entire facility—not just your label scanning.&lt;/p&gt;
&lt;p&gt;Or start building today with our &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;14-day free trial&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/</id>
        <title>How to Ingest CSV Logs into MQTT, Databases, and Dashboards</title>
        <summary>Turn old CSV logs into live data streams using FlowFuse.</summary>
        <updated>2025-11-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;If you work in manufacturing, you likely have gigabytes of data in CSV files—temperature logs, production counts, machine status records. The data exists and is organized, but it&#39;s not accessible to the systems that need it.&lt;/p&gt;
&lt;p&gt;PLCs log directly to CSV through proprietary software. Legacy SCADA systems write flat files. Custom applications generate daily reports. These systems are reliable, but they weren&#39;t built to integrate with MQTT brokers or databases.&lt;/p&gt;
&lt;p&gt;If you&#39;re using FlowFuse to log data, you can send to MQTT and databases as data flows through FlowFuse. But if your CSV files come from PLCs, SCADA systems, or other external tools, you need to read and ingest them after they&#39;re written.&lt;/p&gt;
&lt;p&gt;This guide shows you how to read CSV files—whether real-time or historical—and route them to MQTT brokers, databases, and dashboards.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before starting, ensure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A running FlowFuse instance. If you don&#39;t have one, &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;sign up for free&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CSV log files with industrial data&lt;/li&gt;
&lt;li&gt;Access to an MQTT broker&lt;/li&gt;
&lt;li&gt;Access to a database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you have an Enterprise account, you won&#39;t need to set up external MQTT brokers or databases, FlowFuse provides these services built into the platform.&lt;/p&gt;
&lt;h3 id=&quot;sample-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#sample-data&quot;&gt;Sample Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don&#39;t have a CSV file and want to follow along, you can import the following flow and deploy it. This flow will simulate a temperature sensor and log readings to a daily CSV file.&lt;/p&gt;
&lt;div id=&quot;nr-flow-250&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow250 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;fill&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.57&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;ac0d35a6466cfcb4&#92;&quot;,&#92;&quot;4aff5b57cbb63b8f&#92;&quot;,&#92;&quot;a5c5746934670306&#92;&quot;,&#92;&quot;23ebc0da4315ac46&#92;&quot;,&#92;&quot;2518dc909d447655&#92;&quot;],&#92;&quot;x&#92;&quot;:214,&#92;&quot;y&#92;&quot;:279,&#92;&quot;w&#92;&quot;:892,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac0d35a6466cfcb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;csv&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;spec&#92;&quot;:&#92;&quot;rfc&#92;&quot;,&#92;&quot;sep&#92;&quot;:&#92;&quot;,&#92;&quot;,&#92;&quot;hdrin&#92;&quot;:true,&#92;&quot;hdrout&#92;&quot;:&#92;&quot;once&#92;&quot;,&#92;&quot;multi&#92;&quot;:&#92;&quot;one&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;r&#92;&quot;,&#92;&quot;temp&#92;&quot;:&#92;&quot;timestamp,temperature&#92;&quot;,&#92;&quot;skip&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;strings&#92;&quot;:true,&#92;&quot;include_empty_strings&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;include_null_values&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a5c5746934670306&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4aff5b57cbb63b8f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Daily PLC Logger&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// @ts-ignore Node ≥ 18.15 provides fs.statfsSync; editor types may lag&#92;&#92;n&#92;&#92;nconst now = new Date();&#92;&#92;nconst dateStr = now.toISOString().split(&#39;T&#39;)[0];&#92;&#92;nconst timestamp = now.toISOString();&#92;&#92;n&#92;&#92;nconst filename = `./plc_data_${dateStr}.csv`;&#92;&#92;n&#92;&#92;nmsg.payload = {&#92;&#92;n    timestamp: timestamp,&#92;&#92;n    temperature: msg.payload,&#92;&#92;n};&#92;&#92;n&#92;&#92;nmsg.filename = filename;&#92;&#92;n&#92;&#92;n// Track last date in flow context&#92;&#92;nconst lastDate = flow.get(&#39;lastDate&#39;) || &#39;&#39;;&#92;&#92;nif (lastDate !== dateStr) {&#92;&#92;n    msg.reset = true; // Will trigger CSV node to write headers&#92;&#92;n    flow.set(&#39;lastDate&#39;, dateStr);&#92;&#92;n} &#92;&#92;n&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac0d35a6466cfcb4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5c5746934670306&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Log Data to CSV file&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:true,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2518dc909d447655&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;23ebc0da4315ac46&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;$round(70 + ($random() * 2), 2)&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4aff5b57cbb63b8f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2518dc909d447655&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5a0080d134f80f7d&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1010,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow250.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-250&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;real-time-data-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#real-time-data-pipeline&quot;&gt;Real-Time Data Pipeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This pipeline monitors CSV files for changes and immediately publishes new data to MQTT topics. Use this approach when you need live data streams for dashboards, alerting systems, or real-time coordination between multiple systems.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-monitoring-csv-files&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-1%3A-monitoring-csv-files&quot;&gt;Step 1: Monitoring CSV Files&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Watch node continuously monitors a directory and triggers whenever a file is created or modified.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Watch node&lt;/strong&gt; onto the canvas and double-click to configure it. Enter the directory path you want to monitor in the Files field, such as &lt;code&gt;/home/user/data/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; onto the canvas to set the correct filename. Configure it to set &lt;code&gt;msg.filename&lt;/code&gt; using a JSONata expression: &lt;code&gt;&amp;quot;plc_data_&amp;quot; &amp;amp; $moment().format(&amp;quot;YYYY-MM-DD&amp;quot;) &amp;amp; &amp;quot;.csv&amp;quot;&lt;/code&gt; which dynamically constructs the filename based on today&#39;s date. If your files use a different naming convention, adjust the expression accordingly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Read File node&lt;/strong&gt; onto the canvas to read the file contents. Set the Filename field to &lt;code&gt;msg.filename&lt;/code&gt; as a message property. Configure the Output as &amp;quot;a single utf8 string&amp;quot; and leave Encoding at Default.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuration screen of the Read File node showing filename set to msg.filename, output format as utf8 string, and default encoding&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/read-file-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuration of the File In node to read CSV file contents&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &lt;strong&gt;Watch node&lt;/strong&gt; to the input of the &lt;strong&gt;Change node&lt;/strong&gt;, and the output of the &lt;strong&gt;Change node&lt;/strong&gt; to the input of the &lt;strong&gt;Read File&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point, whenever a CSV file in your monitored directory is created or modified, the flow reads its contents. The raw CSV data is now in &lt;code&gt;msg.payload&lt;/code&gt; as a text string, ready to be parsed.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-parsing-csv-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-2%3A-parsing-csv-data&quot;&gt;Step 2: Parsing CSV Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll convert the raw CSV text into structured data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;CSV node&lt;/strong&gt; onto the canvas and connect it to the File In node output. Double-click to configure it to set:
&lt;ul&gt;
&lt;li&gt;Separator: Comma&lt;/li&gt;
&lt;li&gt;Parser: RFC4180&lt;/li&gt;
&lt;li&gt;Check &amp;quot;First row contains column names&amp;quot; and &amp;quot;Parse numerical values&amp;quot;&lt;/li&gt;
&lt;li&gt;Output: &amp;quot;a single message [array]&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;CSV node configuration showing comma separator, RFC4180 parser, first row as column names, parse numerical values enabled, and output as single message array&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/csv-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;CSV parser configuration for batch processing with RFC4180 standard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The CSV node now converts the raw text into an array of objects, where each object represents a row with named properties from the column headers.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-extracting-the-latest-record&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-3%3A-extracting-the-latest-record&quot;&gt;Step 3: Extracting the Latest Record&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since we’re reading the entire file each time it changes, we only need to publish the most recent data point to MQTT.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Function node&lt;/strong&gt; onto the canvas and connect it to the CSV node output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add this code to extract only the latest row:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-156&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-156&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// msg.payload is an array of all CSV rows&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Extract only the latest row&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rows &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// No data in file yet&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-156&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your parsed data now flows through as individual records, ready to be published to MQTT.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-publishing-to-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-4%3A-publishing-to-mqtt&quot;&gt;Step 4: Publishing to MQTT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll publish the parsed CSV data to an MQTT broker for real-time distribution. If you have FlowFuse Team or Enterprise tier, &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-3%3A-set-up-mqtt-with-flowfuse&quot;&gt;enable the MQTT broker within your FlowFuse team&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;adding-context-to-your-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#adding-context-to-your-data&quot;&gt;Adding Context to Your Data&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; onto the canvas and connect it to the output of the &lt;strong&gt;Function node&lt;/strong&gt;. This step adds useful context for better data traceability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the node to set &lt;code&gt;msg.payload&lt;/code&gt; to a structured object—customize it based on your data and application needs:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-188&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-188&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;site&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tokyo_plant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;line&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;assembly_line_a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;device&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;press_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;measurement&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;celsius&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-188&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;configuring-the-mqtt-publisher&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#configuring-the-mqtt-publisher&quot;&gt;Configuring the MQTT Publisher&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;ff-mqtt-out node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;Change node&lt;/strong&gt;. When you drag the node, it will be automatically configured with the FlowFuse MQTT broker—you do not need to manually add configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;By default, the client automatically created for your instance only has &lt;strong&gt;subscribe&lt;/strong&gt; permissions. Click &lt;strong&gt;Configure Access Control&lt;/strong&gt; next to the server in the node configuration window. This will redirect you to the platform’s broker client management page, filtered to show the client associated with this instance. Click the &lt;strong&gt;Edit&lt;/strong&gt; button, enable both &lt;strong&gt;Publish&lt;/strong&gt; and &lt;strong&gt;Subscribe&lt;/strong&gt; actions, and then restart your instance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &lt;strong&gt;topic&lt;/strong&gt; following ISA-95 hierarchy:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;company/site/area/line/cell/device/measurement
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;acme/tokyo/assembly/line-a/press-01/temperature
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Configure the &lt;strong&gt;QoS level&lt;/strong&gt; in the MQTT node. Set it to QoS 1 for reliable delivery—this ensures your data reaches subscribers even if there are brief network issues, or choose according to your reliability requirements (QoS 0 for high-frequency non-critical data, QoS 2 for critical data).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the MQTT Out node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/csv-to-mqtt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the MQTT Out node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;batch-processing-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#batch-processing-pipeline&quot;&gt;Batch Processing Pipeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This pipeline reads CSV files on a schedule and writes data to databases in efficient batches. Use this approach for historical data storage, trend analysis, and reporting where immediate writes aren&#39;t necessary.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-reading-csv-files-on-schedule&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-1%3A-reading-csv-files-on-schedule&quot;&gt;Step 1: Reading CSV Files on Schedule&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unlike the real-time pipeline that watches for file changes, batch processing runs on a timer.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject node&lt;/strong&gt; onto the canvas. Configure it to trigger on your desired schedule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For hourly batches: Set repeat interval to &amp;quot;interval&amp;quot; and enter 1 hour&lt;/li&gt;
&lt;li&gt;For shift-based batches: Add multiple inject nodes, For example, one at 08:00 for night shift end, another at 16:00 for day shift end, and a third at 00:00 for evening shift end.&lt;/li&gt;
&lt;li&gt;For daily batches: Set to trigger &amp;quot;at a specific time&amp;quot; once per day&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; and configure it to set &lt;code&gt;msg.filename&lt;/code&gt; to your CSV file path. Use a JSONata expression if you need dynamic filenames: &lt;code&gt;&amp;quot;plc_data_&amp;quot; &amp;amp; $moment().format(&amp;quot;YYYY-MM-DD&amp;quot;) &amp;amp; &amp;quot;.csv&amp;quot;&lt;/code&gt;. If your files use a different naming convention, adjust the expression accordingly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Read File node&lt;/strong&gt; onto the canvas to read the file contents. Set the Filename field to &lt;code&gt;msg.filename&lt;/code&gt; as a message property. Configure the Output as &amp;quot;a single utf8 string&amp;quot; and leave Encoding at Default.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &lt;strong&gt;Inject node&lt;/strong&gt; to the input of the &lt;strong&gt;Change node&lt;/strong&gt;, and the output of the &lt;strong&gt;Change node&lt;/strong&gt; to the input of the &lt;strong&gt;Read File&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-2%3A-parsing-all-records&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-2%3A-parsing-all-records&quot;&gt;Step 2: Parsing All Records&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;CSV node&lt;/strong&gt; and connect it to the File In node output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure it the same way as in the real-time pipeline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separator: Comma&lt;/li&gt;
&lt;li&gt;Parser: RFC4180&lt;/li&gt;
&lt;li&gt;Check &amp;quot;First row contains column names&amp;quot; and &amp;quot;Parse numerical values&amp;quot;&lt;/li&gt;
&lt;li&gt;Output: &amp;quot;a single message [array]&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-3%3A-filtering-new-records&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-3%3A-filtering-new-records&quot;&gt;Step 3: Filtering New Records&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since we’re reading the entire CSV file each time, we need to track which rows have already been written to the database to avoid duplicates.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Function node&lt;/strong&gt; and connect it to the &lt;strong&gt;CSV node&lt;/strong&gt; output. Add this code:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-332&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-332&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; allRows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Get the last processed row count from flow context&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastRowCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lastRowCount&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Get only new rows since last processing&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newRows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; allRows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lastRowCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newRows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Update the row count for next run&lt;/span&gt;&lt;br /&gt;    flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lastRowCount&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; allRows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newRows&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// No new data to process&lt;/span&gt;&lt;br /&gt;    node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No new records to process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-332&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-4%3A-inserting-to-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-4%3A-inserting-to-database&quot;&gt;Step 4: Inserting to Database&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll configure the database insertion to write batched data efficiently.&lt;/p&gt;
&lt;h4 id=&quot;enabling-flowfuse-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#enabling-flowfuse-database&quot;&gt;Enabling FlowFuse Database&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you have a Enterprise account, you can use the built-in PostgreSQL database service instead of setting up an external database. Follow the instructions in &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#step-1%3A-enable-the-database-in-your-project&quot;&gt;Getting Started with FlowFuse Tables&lt;/a&gt; to enable the database in your project.&lt;/p&gt;
&lt;p&gt;Once enabled, you&#39;ll have access to a fully managed PostgreSQL database that&#39;s automatically configured and ready to use with your FlowFuse flows.&lt;/p&gt;
&lt;h4 id=&quot;creating-the-database-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#creating-the-database-table&quot;&gt;Creating the Database Table&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Before inserting data, you need to create a table to store your sensor readings.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In your Node-RED editor, drag a &lt;strong&gt;Query node&lt;/strong&gt; onto the canvas. Just like the FlowFuse MQTT nodes, it will automatically configure itself when added to the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click to open it and click &lt;strong&gt;&amp;quot;Ask the FlowFuse Expert&amp;quot;&lt;/strong&gt; at the top of the configuration dialog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the assistant prompt, enter:
&lt;em&gt;“Create a new table named &lt;code&gt;sensor_data&lt;/code&gt; to store sensor readings with the following columns: &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;site&lt;/code&gt;, &lt;code&gt;line&lt;/code&gt;, &lt;code&gt;device&lt;/code&gt;, &lt;code&gt;measurement&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, and &lt;code&gt;unit&lt;/code&gt;.”&lt;/em&gt;, Modify the table name and columns as needed to match your specific data and application requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;&amp;quot;Ask the FlowFuse Expert&amp;quot;&lt;/strong&gt; button. The assistant will generate the SQL query for you and automatically populate it in the Query field.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject node&lt;/strong&gt; onto the canvas, set it to trigger once, and connect it to the &lt;strong&gt;Query node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Debug node&lt;/strong&gt; connected to the &lt;strong&gt;Query node&lt;/strong&gt; output to see the result.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the Inject button to create the table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;preparing-data-for-batch-insert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#preparing-data-for-batch-insert&quot;&gt;Preparing Data for Batch Insert&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Instead of writing each CSV row individually to the database, we&#39;ll use batch inserts for much better performance. A single transaction with many rows is far more efficient than many separate transactions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Function node&lt;/strong&gt; onto the canvas and connect it to the previous &lt;strong&gt;Function node&lt;/strong&gt; (the one that filters new records).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name this node &amp;quot;Prepare Batch Insert&amp;quot; and add the following code:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-409&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-409&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// msg.payload contains the new rows from CSV&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newRows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Transform each row to match your database schema&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formattedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newRows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tokyo_plant&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;assembly_line_a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;press_01&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;measurement&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;temperature&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;celsius&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Generate parameter placeholders for batch insert&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Each row has 7 fields, so we need 7 parameters per row&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Example: ($1,$2,$3,$4,$5,$6,$7), ($8,$9,$10,$11,$12,$13,$14), ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formattedData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;($&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Build the SQL insert query with placeholders, modify the query according to your table name and schema.&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;    INSERT INTO sensor_data &lt;br /&gt;    (timestamp, site, line, device, measurement, value, unit)&lt;br /&gt;    VALUES &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;values&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Flatten the data into a single array of parameters&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Order must match the columns in the INSERT statement&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formattedData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;site&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;line&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;measurement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unit&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-409&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This function generates a parameterized SQL query that inserts all rows in a single database transaction, which is significantly faster than individual inserts.&lt;/p&gt;
&lt;h2 id=&quot;visualizing-csv-data-on-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#visualizing-csv-data-on-dashboard&quot;&gt;Visualizing CSV Data on Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we&#39;ve ingested CSV data into MQTT and databases, let&#39;s visualize it on a dashboard. We&#39;ll focus on real-time visualization using the MQTT pipeline we built earlier. For historical data visualization from FlowFuse Tables, refer to our comprehensive guide: &lt;a href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/&quot;&gt;Building Time-Series Dashboards with FlowFuse Tables&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;step-1%3A-installing-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-1%3A-installing-dashboard&quot;&gt;Step 1: Installing Dashboard&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;In your Node-RED editor, click the hamburger menu (≡) in the top right corner.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; and confirm.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;step-2%3A-subscribing-to-mqtt-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-2%3A-subscribing-to-mqtt-data&quot;&gt;Step 2: Subscribing to MQTT Data&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ff-mqtt-in node&lt;/strong&gt; onto the canvas.&lt;/li&gt;
&lt;li&gt;Configure the Topic to match your publisher: &lt;code&gt;acme/tokyo/assembly/line-a/press-01/temperature&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Output&lt;/strong&gt; to &amp;quot;auto-detect (string or buffer)&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the MQTT Out node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-to-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the MQTT Out node&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;step-3%3A-creating-the-dashboard-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#step-3%3A-creating-the-dashboard-widgets&quot;&gt;Step 3: Creating the Dashboard Widgets&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now we&#39;ll add a chart to visualize the temperature data in real-time.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-chart&lt;/strong&gt; widget onto the canvas and double-click it. Create a new UI group for it to render.&lt;/li&gt;
&lt;li&gt;Set the size according to your needs for the chart, label to &amp;quot;Temperature&amp;quot;, type to &amp;quot;line&amp;quot;, action to &amp;quot;append&amp;quot;, and x-axis to &amp;quot;timescale&amp;quot;.&lt;/li&gt;
&lt;li&gt;Next, set series to &lt;code&gt;msg.payload.device&lt;/code&gt;, x to &lt;code&gt;msg.payload.timestamp&lt;/code&gt;, and y to &lt;code&gt;msg.payload.value&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI Chart configuration showing line chart type, append action, timescale x-axis, with series, x, and y values mapped to payload properties&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/chart-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Chart widget configuration for real-time temperature visualization&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, open the dashboard — you should see a real-time line chart displaying temperature values over time, with each device shown as a separate series. Data points will automatically update as new MQTT messages arrive.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dashboard showing real-time line chart with temperature data updating as new MQTT messages arrive&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-dashboard.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Live dashboard displaying real-time temperature readings from CSV data stream&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/csv-mqtt-database-dashboard-flowfuse/#what&#39;s-next&quot;&gt;What&#39;s Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;ve transformed static CSV files into live data streams that flow through MQTT, databases, and dashboards. Your legacy equipment now communicates with modern systems without any hardware changes.&lt;/p&gt;
&lt;p&gt;This tutorial walked you through building a data pipeline. FlowFuse takes it further by handling both development and production deployment. When you need to scale across multiple production lines, manage team collaboration, deploy to hundreds of devices remotely, or maintain infrastructure like MQTT brokers and databases, FlowFuse provides the platform to do it all. As you saw, it also includes an FlowFuse Expert to speed up your workflow.&lt;/p&gt;
&lt;p&gt;If you want to see more on how FlowFuse helps with scaling and production deployments, &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt; today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/</id>
        <title>The Industrial IoT Market Shift: What the PTC Divestment Means for Your Data Strategy</title>
        <summary>Understanding the bigger picture behind the $600M Kepware and ThingWorx sale</summary>
        <updated>2025-11-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/"/>
        <author><name>Pablo Filomeno</name></author>
        <content type="html">&lt;p&gt;The news of PTC selling Kepware and ThingWorx to TPG for $600 million has caused a significant impact across the industrial automation sector. For anyone working in manufacturing, OT data integration, or industrial IoT, this divestment raises important questions about the future direction of these widely-used platforms, and what it means for organizations relying on them.&lt;/p&gt;
&lt;p&gt;But here&#39;s the thing: this isn&#39;t an isolated event. Back in July 2024, there were rumors that Autodesk might acquire PTC for $20+ billion. Those talks ultimately fell through when Autodesk walked away from the deal. Now, just months later, PTC has decided to divest two of its major industrial IoT assets. The pattern is clear: PTC is refocusing its strategy.&lt;/p&gt;
&lt;h2 id=&quot;a-strategic-realignment%2C-not-a-surprise&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#a-strategic-realignment%2C-not-a-surprise&quot;&gt;A Strategic Realignment, Not a Surprise&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PTC has been under strategic pressure for some time. The company operates across multiple domains: CAD and PLM (with Creo and Windchill), Application Lifecycle Management (ALM) with Codebeamer, and Industrial IoT with Kepware and ThingWorx. While this portfolio diversity has value, it also creates complexity, and when Autodesk considered acquiring PTC earlier this year, that complexity likely played a role in their decision to walk away.&lt;/p&gt;
&lt;p&gt;Now, PTC is taking action on its own. By divesting Kepware and ThingWorx to TPG, the company is narrowing its focus to what it calls its &amp;quot;Intelligent Product Lifecycle&amp;quot; vision, concentrating on CAD, PLM, ALM, SLM (Service Lifecycle Management), and the integration of AI and SaaS across these core areas.&lt;/p&gt;
&lt;p&gt;For PTC, this makes sense. Kepware and ThingWorx solve different problems than the rest of their portfolio. They&#39;re about OT data connectivity and IIoT application development (areas that don&#39;t naturally integrate with product design and lifecycle management). By selling these assets to TPG, PTC can focus resources on its core business while TPG invests in growing the connectivity and IoT platforms.&lt;/p&gt;
&lt;p&gt;But for customers, this introduces uncertainty: What does life under TPG ownership look like?&lt;/p&gt;
&lt;h2 id=&quot;the-customer-reality%3A-uncertainty-and-opportunity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#the-customer-reality%3A-uncertainty-and-opportunity&quot;&gt;The Customer Reality: Uncertainty and Opportunity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For organizations using Kepware or ThingWorx, this transition will bring uncertainty. Product roadmaps may shift. Pricing structures could change. Integration strategies may no longer make sense in the same way. Even if TPG commits to investing in these platforms, the reality is that customers are now operating in a period of transition (and transitions often, if not always, bring risk).&lt;/p&gt;
&lt;p&gt;This is precisely why, back in July when the Autodesk acquisition rumors started, we launched our migration landing page at flowfuse.com/vs/kepware. To leave things clear. To make a clear statement. We saw what was coming. Organizations that had built their OT data strategies on these platforms would soon be re-evaluating their options. And for many, this is the perfect moment to ask a more fundamental question: what should a modern industrial data integration platform actually look like?&lt;/p&gt;
&lt;h2 id=&quot;the-open-source-alternative%3A-built-by-node-red&#39;s-founder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#the-open-source-alternative%3A-built-by-node-red&#39;s-founder&quot;&gt;The Open-Source Alternative: Built by Node-RED&#39;s Founder&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At FlowFuse, we take a fundamentally different approach to industrial data integration. We&#39;re not a closed, proprietary platform tied to a single vendor&#39;s roadmap or business priorities. Instead, we&#39;re built on Node-RED, the truly open-source, low-code programming tool created by Nick O&#39;Leary, who is also the founder of FlowFuse.&lt;/p&gt;
&lt;p&gt;This isn&#39;t just a technical detail but it&#39;s a strategic advantage. Here&#39;s why:&lt;/p&gt;
&lt;p&gt;FlowFuse vs. Kepware: A Clear Comparison&lt;/p&gt;
&lt;p&gt;For organizations evaluating their options, the differences between FlowFuse and traditional platforms like Kepware become clear when you compare them side by side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Open-source foundation: FlowFuse is built on Node-RED and the open-source ecosystem, giving you full transparency and control. Kepware, by contrast, is a proprietary stack with limited visibility into how it works.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zero vendor lock-in: With FlowFuse, your flows are portable. You can run them anywhere (cloud, on-premises, or at the edge). Kepware ties you to their licensing model and roadmap.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Integration flexibility: Node-RED&#39;s 5,000+ community-contributed nodes mean you can connect to virtually anything (MQTT, OPC-UA, REST APIs, SQL databases, cloud services, and more). Kepware&#39;s integrations are often limited to proprietary or custom connectors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transparent pricing: FlowFuse offers use-based, transparent pricing that scales with your needs. Kepware&#39;s licensing model is tiered, often creating cost barriers as you grow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Active community: Node-RED has one of the largest and most active open-source communities in industrial automation. You&#39;re not dependent on a single vendor for support, innovation, or problem-solving. Kepware operates in a closed ecosystem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Future-proof architecture: FlowFuse is cloud-ready, portable, and designed to evolve with your infrastructure. After multiple ownership transitions, Kepware&#39;s future direction under TPG remains uncertain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can explore these differences in detail at https://flowfuse.com/vs/kepware.&lt;/p&gt;
&lt;h2 id=&quot;connect-to-anything%2C-collect-everything&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#connect-to-anything%2C-collect-everything&quot;&gt;Connect to Anything, Collect Everything&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED has over 5,000 community-contributed nodes, covering virtually every industrial protocol, database, cloud service, and API you can imagine. Whether you need to pull data from a Siemens S7 PLC, a Modbus device, an OPC UA server, push it to AWS IoT Core, Azure, or your own database, transform it in real-time, and visualize it on a custom dashboard. Node-RED can do it all.&lt;/p&gt;
&lt;p&gt;And because it&#39;s open source, if a connector doesn&#39;t exist, you or the community can build it. This level of connectivity is unmatched. Kepware is powerful for protocol translation, sure, but it&#39;s primarily focused on moving data from OT systems to IT systems. Node-RED, by contrast, is a full data orchestration platform. You&#39;re not just collecting data, you&#39;re transforming, routing, analyzing, and acting on it, all in one place.&lt;/p&gt;
&lt;h3 id=&quot;no-vendor-lock-in%2C-ever&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#no-vendor-lock-in%2C-ever&quot;&gt;No Vendor Lock-In, Ever&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With proprietary platforms, your data integration strategy is tied to the vendor&#39;s business decisions. Pricing changes? You adapt. Features deprecated? You work around it. Company gets acquired? You hope for the best.&lt;/p&gt;
&lt;p&gt;With Node-RED and FlowFuse, you&#39;re in control. The core technology is open source, maintained by a thriving global community. FlowFuse adds the enterprise-grade management, security, and scalability that industrial organizations need, but you&#39;re never locked in. If you ever decide FlowFuse isn&#39;t the right fit, your Node-RED flows are yours to take and run elsewhere. That&#39;s the power of true open source.&lt;/p&gt;
&lt;h3 id=&quot;enterprise-ready-from-day-one&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#enterprise-ready-from-day-one&quot;&gt;Enterprise-Ready from Day One&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the challenges with open-source tools is that they often require significant effort to operationalize at scale. That&#39;s where FlowFuse comes in. We provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Centralized management of Node-RED instances across multiple sites and edge devices&lt;/li&gt;
&lt;li&gt;DevOps-ready workflows with version control, CI/CD integration, and team collaboration features&lt;/li&gt;
&lt;li&gt;Enterprise security with role-based access control, audit logs, and compliance-ready deployment options&lt;/li&gt;
&lt;li&gt;Scalability to manage thousands of edge devices or cloud-based instances from a single platform&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, FlowFuse gives you the flexibility and openness of Node-RED with the operational rigor that enterprise IT and OT teams require.&lt;/p&gt;
&lt;p&gt;To learn more take a quick look at this video and learn about these 5 reasons you should migrate to FlowFuse. https://youtu.be/fUqfA521Iqg&lt;/p&gt;
&lt;h2 id=&quot;simple%2C-visual%2C-and-incredibly-powerful&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#simple%2C-visual%2C-and-incredibly-powerful&quot;&gt;Simple, Visual, and Incredibly Powerful&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED&#39;s low-code, visual programming interface makes it accessible to engineers who aren&#39;t developers, while still being powerful enough for complex industrial applications. You wire together nodes to create data flows, connecting sources, transforming data, triggering actions, and building dashboards. It&#39;s intuitive, fast to prototype, and easy to maintain.&lt;/p&gt;
&lt;p&gt;This means faster time-to-value. Instead of waiting months for vendor implementations or custom development, your team can build and deploy solutions in days or weeks. And because everything is visual, it&#39;s easier to document, troubleshoot, and hand off to other team members.&lt;/p&gt;
&lt;h2 id=&quot;what-this-means-for-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#what-this-means-for-you&quot;&gt;What This Means for You&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re currently using Kepware or ThingWorx, this transaction isn&#39;t necessarily bad news. TPG may very well invest in these platforms and accelerate their development. But it&#39;s also a reminder of a fundamental truth in enterprise software: when you build on proprietary platforms, you are always subject to the strategic priorities of the company that owns them.&lt;/p&gt;
&lt;p&gt;This is a good time to ask some strategic questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is your data integration platform aligned with your long-term strategy?Or are you constantly adapting to vendor-driven changes?&lt;/li&gt;
&lt;li&gt;Can you extend and customize your platform to meet your unique needs? Or are you constrained by what the vendor offers?&lt;/li&gt;
&lt;li&gt;Do you have flexibility in how and where you deploy? Cloud, on-premises, edge, hybrid, can your platform handle all of these?&lt;/li&gt;
&lt;li&gt;What happens if your vendor’s priorities shift again? Are you prepared for another transition?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For organizations re-evaluating their options, open-source platforms like Node-RED and FlowFuse offer a compelling alternative. You get the connectivity, flexibility, and control to build exactly the data strategy you need, without being tied to a single vendor’s roadmap or business model.&lt;/p&gt;
&lt;h2 id=&quot;the-path-forward&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#the-path-forward&quot;&gt;The Path Forward&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The industrial automation market is evolving rapidly. As companies like PTC realign their portfolios, the organizations that thrive will be the ones that build on flexible, future-proof foundations.&lt;/p&gt;
&lt;p&gt;At FlowFuse, we believe that foundation is open source. It&#39;s why we&#39;ve built our platform on Node-RED, created by our founder Nick O&#39;Leary. And it&#39;s why we&#39;re committed to giving industrial organizations the tools they need to take control of their data strategies, with the flexibility to adapt, the power to innovate, and the freedom to choose their own path.&lt;/p&gt;
&lt;h2 id=&quot;ready-to-explore-your-options%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/11/ptc-kepware-thingworx-divestment/#ready-to-explore-your-options%3F&quot;&gt;Ready to Explore Your Options?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re evaluating your options, whether you&#39;re currently on Kepware, ThingWorx, or another platform, &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;we&#39;d love to talk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://flowfuse.com/vs/kepware/&quot;&gt;how we stack up against Kepware&lt;/a&gt; to learn more about how FlowFuse compares to traditional industrial connectivity platforms, or &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact our team&lt;/a&gt; to speak with one of our Migration Experts. We can help you understand your options, plan a migration strategy, and show you how open-source industrial data integration can transform your operations.&lt;/p&gt;
&lt;p&gt;The industrial IoT market is shifting. Make sure your data strategy is built to adapt.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/</id>
        <title>How to Connect Any PLC to MQTT in Under an Hour</title>
        <summary>Connect any PLC to MQTT without the typical complexity, costs, and expertise requirements</summary>
        <updated>2025-10-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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&#39;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.&lt;/p&gt;
&lt;p&gt;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&#39;s hard to find.&lt;/p&gt;
&lt;p&gt;This guide cuts through that complexity. You&#39;ll learn how to connect PLCs using MQTT without the typical headaches. We&#39;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.&lt;/p&gt;
&lt;h2 id=&quot;why-plc-to-cloud-gets-so-complicated&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#why-plc-to-cloud-gets-so-complicated&quot;&gt;Why PLC-to-Cloud Gets So Complicated&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into the solution, it&#39;s worth understanding why this is so difficult.&lt;/p&gt;
&lt;p&gt;First, there&#39;s the proprietary protocols. Factory floors have PLCs from different manufacturers, each speaking their own language: Modbus, OPC-UA, Ethernet/IP, Profinet, FINS, etc. Getting data out means dealing with all of them at once, maintaining multiple drivers and troubleshooting different failure modes.&lt;/p&gt;
&lt;p&gt;Then there&#39;s the networking challenge. Factory networks weren&#39;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;And there&#39;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A properly configured and fully operational PLCs, located on the same network as the edge device that will be reading its data.&lt;/li&gt;
&lt;li&gt;A running FlowFuse instance on your edge device. If you do not have an account, &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;sign up for a free trial&lt;/a&gt; and set up your instance following the instructions in this article.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now, let&#39;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.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;vptAoDR78Cc&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;step-1%3A-extract-data-from-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-1%3A-extract-data-from-your-plc&quot;&gt;Step 1: Extract Data from Your PLC&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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/IP, 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The Node-RED ecosystem that powers FlowFuse offers comprehensive protocol support. You&#39;ll find nodes available for every major PLC manufacturer, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-modbus&lt;/code&gt; – Modbus RTU/TCP PLCs and devices&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-s7&lt;/code&gt; – Siemens S7-300/400/1200/1500&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-opcua&lt;/code&gt; – OPC UA servers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-cip-ethernet-ip&lt;/code&gt; – Allen-Bradley PLCs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-mcprotocol&lt;/code&gt; – Mitsubishi PLCs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-omron-fins&lt;/code&gt; – Omron PLCs&lt;/li&gt;
&lt;li&gt;and many more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adding a protocol node to your FlowFuse instance takes just a few clicks. Open the palette manager from the hamburger menu, select &lt;strong&gt;Manage palette&lt;/strong&gt;, go to the &lt;strong&gt;Install&lt;/strong&gt; tab, and search for the node you need.&lt;/p&gt;
&lt;h2 id=&quot;convincing-the-it-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#convincing-the-it-team&quot;&gt;Convincing the IT Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When talking to people in the IIoT community, one recurring challenge always comes up—&lt;strong&gt;convincing the IT team&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;FlowFuse solves this with an &lt;strong&gt;edge-first architecture&lt;/strong&gt;. 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 &lt;strong&gt;outbound&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;From a security standpoint, this changes everything. Your firewall configuration does not change.&lt;br /&gt;
No new inbound rules. No DMZ setup. No VPN tunnels to maintain.&lt;/p&gt;
&lt;p&gt;The device agent behaves like any other business application making secure outbound HTTPS requests—something your network already allows.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;step-2%3A-transform-and-structure-your-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-2%3A-transform-and-structure-your-data&quot;&gt;Step 2: Transform and Structure Your Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visual Transformation with Change Nodes and JSONata&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Plant engineers can work directly with these visual tools—no programming required.&lt;/p&gt;
&lt;p&gt;For example, suppose you are receiving a pressure sensor value as &lt;code&gt;msg.payload&lt;/code&gt; but it lacks context.&lt;/p&gt;
&lt;p&gt;You can use a &lt;strong&gt;Change&lt;/strong&gt; node to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add contextual information such as the machine ID, facility, or sensor location, unit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node adding context to data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-adding-context.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node used to convert temperature and add machine context&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function Nodes for Custom Logic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tip: Use the &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert&lt;/a&gt; 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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-built Community Nodes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;For example, a popular node I&#39;m using in my demo for parsing and transforming data is &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt;. 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.&lt;/p&gt;
&lt;h2 id=&quot;step-3%3A-set-up-mqtt-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#step-3%3A-set-up-mqtt-with-flowfuse&quot;&gt;Step 3: Set Up MQTT with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;To use the FlowFuse MQTT broker, you&#39;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.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Enabling FlowFuse MQTT Broker&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-broker.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Enabling FlowFuse MQTT Broker&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure Publishing&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;FlowFuse MQTT Out&lt;/strong&gt; node onto your canvas.&lt;/li&gt;
&lt;li&gt;Open the node configuration. It will automatically pick up its configuration.&lt;/li&gt;
&lt;li&gt;Set the topic following ISA-95 hierarchy:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;company/site/area/line/cell/device/measurement
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;acme/plant-a/assembly/line1/press-1/pressure01/bar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why ISA-95 for MQTT Topics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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&#39;re building toward a Unified Namespace (UNS)—a single, consistent way to organize all operational data across your entire organization.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;ISA-95 makes this possible because it maps to how factories actually operate. &lt;code&gt;company/site/area/line/cell&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;This enables powerful wildcard subscriptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;acme/#&lt;/code&gt; - all company data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acme/chicago/#&lt;/code&gt; - single site&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+/+/assembly/#&lt;/code&gt; - assembly operations everywhere&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acme/chicago/assembly/line2/#&lt;/code&gt; - one production line&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note: Use lowercase with hyphens for multi-word names.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Set &lt;strong&gt;QoS&lt;/strong&gt; to &lt;strong&gt;1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After deploying the flow, the MQTT client for your device will be automatically created. To configure access:&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Double-click the MQTT Out node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Configure Access Control&lt;/strong&gt;. You will be redirected to the platform&#39;s broker client management section, filtered to show the client created for this instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configure MQTT Client Access Control&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/configure-access-control.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configure MQTT Client Access Control&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Click the client &lt;strong&gt;edit&lt;/strong&gt;, select &lt;strong&gt;Publish&lt;/strong&gt;, and then click &lt;strong&gt;Confirm&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring Client Access Control&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/client-access-control.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configure MQTT Client Access Control&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That&#39;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&#39;ll see all the topics within your MQTT broker. By clicking &lt;strong&gt;Open Schema&lt;/strong&gt;, you can view the auto-generated schema document created by FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Topic Hierarchy View&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-topic-hierarchy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Topic Hierarchy View&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Topic schema auto-generated by FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-topic-schema-document.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Topic schema auto-generated by FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;bridging-the-expertise-gap-and-cutting-costs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#bridging-the-expertise-gap-and-cutting-costs&quot;&gt;Bridging the Expertise Gap and Cutting Costs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let&#39;s talk about the remaining problems: the expertise gap and cost. FlowFuse solves both by changing how the work gets done.&lt;/p&gt;
&lt;p&gt;Plant engineers configure PLC connections, transform data, contextualize it, and send it to MQTT through drag-and-drop interfaces without writing code—that&#39;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&#39;s domain.&lt;/p&gt;
&lt;p&gt;The FlowFuse Expert fills remaining gaps—describe what you need in plain English, and it generates function nodes, database queries, or dashboard components. Click &amp;quot;Explain&amp;quot; on any flow to get instant documentation.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;get-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/#get-started&quot;&gt;Get Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Connect your first PLC today. &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Sign up for FlowFuse&lt;/a&gt;, 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.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/</id>
        <title>FlowFuse 2.23: MCP and ONNX nodes, FlowFuse AI Expert on the homepage, Application-level Permission Control, FlowFuse Expert for Self-Hosted, and more!</title>
        <summary>MCP and ONNX nodes, FlowFuse AI Expert on the homepage, Application-level Permission Control, FlowFuse Expert for Self-Hosted, and more!</summary>
        <updated>2025-10-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;In this exciting release, we&#39;ve shipped several features that accelerate development in Node-RED using AI, enable creation of AI agents using new Model Context Protocol nodes, provide application-level access controls for much more sophisticated user permissions management, and put an expert flow creator right on our homepage. It&#39;s a big one! Let&#39;s have a look.&lt;/p&gt;
&lt;h2 id=&quot;mcp-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#mcp-nodes&quot;&gt;MCP Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of MCP nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[MCP nodes in the Node-RED palette, ready for use]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With this release, you can now create a Model Context Protocol server using Node-RED. The new MCP nodes enable the creation of a MCP server so that you can create AI agents that will rely on the exact data that you want to surface to an LLM. As AI services rely upon data presented to them, whether it&#39;s anything available on the world wide web (as with LLMs generically) or more focused information, our MCP nodes provide the ability to expose specific resources so that an AI service will rely upon the right data without making all of your information public. It&#39;s a really exciting development. Check out &lt;a href=&quot;https://flowfuse.com/changelog/2025/10/mcp-nodes/&quot;&gt;the Changelog entry&lt;/a&gt; for more.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-ai-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#flowfuse-ai-nodes&quot;&gt;FlowFuse AI Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While MCP makes it possible to create AI agents to rely on the data you have chosen, the new FlowFuse AI nodes allow you to connect AI models of your choosing--including ones that you have trained yourself--to Node-RED to create any workflow you like. The ONNX (Open Neural Network Exchange) format lets you connect a model for whatever purpose you have in mind. This package ships with nodes for running your own custom-trained model, for classifying images, for object detection, and for image depth estimation. This is a huge step in the direction of fully-controlled AI automation inside of Node-RED on FlowFuse.&lt;/p&gt;
&lt;p&gt;For self-hosted customers, once you&#39;ve upgraded, contact &lt;a href=&quot;https://flowfuse.com/support&quot;&gt;FlowFuse Support&lt;/a&gt; to get access to these exciting new nodes.&lt;/p&gt;
&lt;h2 id=&quot;application-level-role-based-access-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#application-level-role-based-access-control&quot;&gt;Application-Level Role-Based Access Control&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of application-level permissions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/rbac2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Control permissions at the application level]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the key features of FlowFuse is the ability to manage Node-RED applications by choosing who gets access to what. Up to now, team owners had to configure permissions at the team level. But what if there are members of your team that should have write permissions to one Node-RED instance, but only viewer access to another? You would have to put those instances on different teams and configure permissions there. With many instances and applications, this could be a headache.&lt;/p&gt;
&lt;p&gt;We&#39;ve solved it. You can now manage permissions at the Application level. Now one and the same team can have users who can access some applications with one level of permissions, and and another application with a different level. We&#39;ve heard your feedback on this need and are happy for you to give it a try!&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#flowfuse-expert&quot;&gt;FlowFuse Expert&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of FlowFuse Expert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/expert.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[The FlowFuse Expert gives step-by-step instructions for building flows]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can now get complete instructions for building a Node-RED flow on &lt;a href=&quot;https://flowfuse.com/&quot;&gt;flowfuse.com&lt;/a&gt; using the FlowFuse Expert! This newest feature in the FlowFuse AI toolkit provides detailed guidance on creating Node-RED flows for any purpose you have in mind.&lt;/p&gt;
&lt;p&gt;Head over to &lt;a href=&quot;https://flowfuse.com/&quot;&gt;flowfuse.com&lt;/a&gt; to check it out! We have big plans in mind for this feature, but can&#39;t say much yet. For now, it&#39;s enough to say that low code development is headed toward a whole new level with FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert-for-self-hosted-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#flowfuse-expert-for-self-hosted-deployments&quot;&gt;FlowFuse Expert for Self Hosted Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of AI assistance, self-hosted FlowFuse deployments have until now not had access to the FlowFuse Expert inside of Node-RED, helping to complete flows using natural language for explanation of flows, creation of Dashboard, Function, and Tables nodes, and Snapshot descriptions. These had been available only to FlowFuse Cloud customers. I&#39;m happy to say that our many self-hosted customers now (finally) can get access to this tool, which helps speed flow creation exponentially. Contact &lt;a href=&quot;https://flowfuse.com/support&quot;&gt;FlowFuse Support&lt;/a&gt; to help get you setup.&lt;/p&gt;
&lt;h2 id=&quot;import-json-at-instance-creation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#import-json-at-instance-creation&quot;&gt;Import JSON at Instance Creation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Developers want the fastest way to spin up a functional Node-RED instance, and we&#39;ve taken another step in that direction by offering the option of uploading a JSON file during the instance creation workflow.&lt;/p&gt;
&lt;h1 id=&quot;sneak-peek&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#sneak-peek&quot;&gt;Sneak Peek&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;What if you could surface your FlowFuse Tables data outside of the FlowFuse environment, for broader consumption as you see fit? Or use data coming into Node-RED to predict maintainance needs? We have exciting things on the way for you!&lt;/p&gt;
&lt;h2 id=&quot;don&#39;t-miss-node-red-con-2025!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#don&#39;t-miss-node-red-con-2025!&quot;&gt;Don&#39;t Miss Node-RED Con 2025!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While not exactly a release item, I&#39;d be remiss if I failed to mention Node-RED Conference 2025! We&#39;ve got a great lineup of speakers who will cover a broad and deep variety of topics on the use of Node-RED. Check out the website and register here: &lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;https://nrcon.nodered.org/.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.23 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.23.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/flowfuse-release-2-23/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/</id>
        <title>How to Log PLC Data to CSV Files</title>
        <summary>Building a reliable, hands-off CSV logging setup with FlowFuse</summary>
        <updated>2025-10-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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&#39;s the format their teams know and trust. If you&#39;re reading this, you&#39;re likely one of them and need a reliable solution.&lt;/p&gt;
&lt;p&gt;CSV files offer something databases can&#39;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&#39;re using.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Meanwhile, databases handle real-time monitoring and automated alerts, cross-functional analytics, high-frequency sensor queries, and dynamic relationships across materials and equipment.&lt;/p&gt;
&lt;p&gt;This isn&#39;t an either/or choice. It&#39;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.
This guide shows how to implement PLC data logging with &lt;strong&gt;FlowFuse&lt;/strong&gt; in a way that keeps running, stable, resilient, and production-ready.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing FlowFuse collecting data from a PLC using OPC UA and logging it to a CSV file.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/plc-to-csv.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing FlowFuse collecting data from a PLC using OPC UA and logging it to a CSV file.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before getting started, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A running FlowFuse instance&lt;/strong&gt; – If you don’t have one yet, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; 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.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-1%3A-setting-up-plc-communication-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#step-1%3A-setting-up-plc-communication-in-flowfuse&quot;&gt;Step 1: Setting Up PLC Communication in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;choosing-your-protocol&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#choosing-your-protocol&quot;&gt;Choosing Your Protocol&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The right protocol depends on what your PLC supports.&lt;/p&gt;
&lt;p&gt;Modern PLCs typically offer open standards like OPC UA, Modbus TCP, or EtherNet/IP. These protocols work across different manufacturers and give you the most flexibility.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Legacy systems use vendor-specific protocols: &lt;a href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/&quot;&gt;S7&lt;/a&gt; for Siemens, MC Protocol for Mitsubishi, FINS for Omron, and &lt;a href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/&quot;&gt;EtherNet/IP&lt;/a&gt; for Allen-Bradley. If your PLC only speaks its native language, Node-RED has dedicated nodes for each one.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-right-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#installing-the-right-node&quot;&gt;Installing the Right Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED&#39;s package ecosystem includes nodes for virtually every industrial protocol. The most common ones are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-modbus&lt;/code&gt; – Modbus RTU/TCP devices&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-s7&lt;/code&gt; – Siemens S7-300/400/1200/1500&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-opcua&lt;/code&gt; – OPC UA servers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-cip-ethernet-ip&lt;/code&gt; – Allen-Bradley PLCs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-mcprotocol&lt;/code&gt; – Mitsubishi Q/L series&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-omron-fins&lt;/code&gt; – Omron PLCs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;configuring-your-connection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#configuring-your-connection&quot;&gt;Configuring Your Connection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Drag the appropriate input node onto your canvas and configure it according to the node&#39;s documentation.&lt;/p&gt;
&lt;h3 id=&quot;verifying-data-quality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#verifying-data-quality&quot;&gt;Verifying Data Quality&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before building your logging flow, verify you&#39;re getting clean, consistent data. Connect a debug node to your PLC input, deploy, and watch the incoming messages.&lt;/p&gt;
&lt;p&gt;You should see values updating at your configured interval with consistent structure and sensible numbers. No connection errors, timeouts, or garbage data.&lt;/p&gt;
&lt;p&gt;If something&#39;s wrong—intermittent connections, bad values, protocol errors—fix it now. Connection problems multiply when you add logging logic on top.&lt;/p&gt;
&lt;p&gt;A stable PLC connection is the foundation. Get this right, and the rest is straightforward.&lt;/p&gt;
&lt;h2 id=&quot;step-2%3A-building-the-basic-csv-logging-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#step-2%3A-building-the-basic-csv-logging-flow&quot;&gt;Step 2: Building the Basic CSV Logging Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With a stable PLC connection verified, you can now build the flow that writes data to CSV files.&lt;/p&gt;
&lt;h3 id=&quot;understanding-the-data-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#understanding-the-data-flow&quot;&gt;Understanding the Data Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The logging system needs four components working together:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PLC input node that collects data at regular intervals&lt;/li&gt;
&lt;li&gt;Function node that adds timestamps and handles daily file rotation&lt;/li&gt;
&lt;li&gt;CSV node that formats data into proper CSV structure&lt;/li&gt;
&lt;li&gt;File node that writes to disk&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;adding-timestamps-and-daily-file-rotation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#adding-timestamps-and-daily-file-rotation&quot;&gt;Adding Timestamps and Daily File Rotation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your PLC data needs timestamps and a way to organize files by date.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a function node onto your canvas&lt;/li&gt;
&lt;li&gt;Connect it to your PLC input node&lt;/li&gt;
&lt;li&gt;Double-click the function node and add this code:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-171&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-171&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; timestamp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create filename with today&#39;s date (YYYY-MM-DD format)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dateStr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;T&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;./plc_data_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dateStr&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.csv&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Structure the data&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; timestamp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;temperature&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;pressure&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pressure&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;flowRate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flowRate&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Store filename for the file node&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-171&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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: &lt;code&gt;plc_data_2025-10-16.csv&lt;/code&gt;, &lt;code&gt;plc_data_2025-10-17.csv&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;h3 id=&quot;formatting-data-with-the-csv-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#formatting-data-with-the-csv-node&quot;&gt;Formatting Data with the CSV Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The CSV node handles all the formatting work—proper escaping, column ordering, and headers.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a CSV node onto your canvas&lt;/li&gt;
&lt;li&gt;Connect it to your function node&lt;/li&gt;
&lt;li&gt;Double-click to configure:
&lt;ul&gt;
&lt;li&gt;Set the columns: &lt;code&gt;timestamp,temperature&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enable &amp;quot;first row contains column names&amp;quot;&lt;/li&gt;
&lt;li&gt;Choose comma as the separator&lt;/li&gt;
&lt;li&gt;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&#39;t break the CSV structure)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing CSV node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/csv-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing CSV node configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The CSV node converts your data object into a properly formatted CSV line with headers included automatically when a new file is created.&lt;/p&gt;
&lt;h3 id=&quot;writing-to-file&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#writing-to-file&quot;&gt;Writing to File&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The file node writes your formatted CSV data to disk.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a file node onto your canvas&lt;/li&gt;
&lt;li&gt;Connect it to your CSV node&lt;/li&gt;
&lt;li&gt;Double-click to configure:
&lt;ul&gt;
&lt;li&gt;Set filename to &lt;code&gt;msg.filename&lt;/code&gt; (uses the dynamic filename from your function)&lt;/li&gt;
&lt;li&gt;Choose &amp;quot;append to file&amp;quot; mode&lt;/li&gt;
&lt;li&gt;Enable &amp;quot;Create directory if it doesn&#39;t exist&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click Done&lt;/li&gt;
&lt;li&gt;Deploy your flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing Write node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/write-file-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing Write node configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let it run. Each day at midnight, the system automatically starts a new file. Old files stay untouched, new data goes to today&#39;s file.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;step-3%3A-monitoring-disk-usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#step-3%3A-monitoring-disk-usage&quot;&gt;Step 3: Monitoring Disk Usage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Running a logging system continuously means files accumulate. Monitor disk space to prevent unexpected failures when storage runs low.&lt;/p&gt;
&lt;p&gt;Add disk space monitoring to prevent unexpected failures.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas and configure it to trigger every hour&lt;/li&gt;
&lt;li&gt;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:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-318&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-318&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Get disk usage information&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stats &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;statfsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalSpace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;blocks &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bsize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; freeSpace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bfree &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bsize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; usedSpace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; totalSpace &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; freeSpace&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; percentUsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usedSpace &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; totalSpace&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;totalGB&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalSpace &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;freeGB&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;freeSpace &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;usedGB&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usedSpace &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;percentUsed&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; percentUsed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Warning threshold&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;percentUsed &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warning &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Disk space critical: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;percentUsed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;% used&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-318&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect it to your notification system to alert when space is critical, for notification you can use &lt;a href=&quot;https://flowfuse.com/node-red/notification/email/&quot;&gt;email&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/node-red/notification/telegram/&quot;&gt;telegram&lt;/a&gt;, discord with &lt;a href=&quot;https://flowfuse.com/node-red/notification/discord/&quot;&gt;FlowFuse&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Deploy the flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you&#39;ll get warnings before disk space becomes critical, giving you time to archive old data or expand storage.&lt;/p&gt;
&lt;h2 id=&quot;step-4%3A-handling-connection-interruptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#step-4%3A-handling-connection-interruptions&quot;&gt;Step 4: Handling Connection Interruptions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Most PLC nodes emit error events when a connection fails. Add error handling to detect and log these events.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a Catch node configured to monitor your PLC input node and Write File node.&lt;/li&gt;
&lt;li&gt;Drag a Function or Change node to format the error messages according to your chosen notification method, and connect it to the Catch node.&lt;/li&gt;
&lt;li&gt;Connect the node that formats the error message to your selected Notification node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below is the complete flow we have built throughout this article.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: When testing with the Inject node, bypass the OPC UA Client and inject data directly into the logger flow.&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-248&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow248 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;fill&#92;&quot;:&#92;&quot;#ffcf3f&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.57&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;ac0d35a6466cfcb4&#92;&quot;,&#92;&quot;4aff5b57cbb63b8f&#92;&quot;,&#92;&quot;a5c5746934670306&#92;&quot;,&#92;&quot;d796d3aee8ea0343&#92;&quot;,&#92;&quot;23ebc0da4315ac46&#92;&quot;,&#92;&quot;181ed86f9c11d1f7&#92;&quot;,&#92;&quot;b34d440897108110&#92;&quot;,&#92;&quot;575ed67714072973&#92;&quot;,&#92;&quot;d08353a9c90b0396&#92;&quot;,&#92;&quot;e719ae6fee22c812&#92;&quot;,&#92;&quot;2518dc909d447655&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:271.5,&#92;&quot;w&#92;&quot;:1112,&#92;&quot;h&#92;&quot;:269.5},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac0d35a6466cfcb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;csv&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;spec&#92;&quot;:&#92;&quot;rfc&#92;&quot;,&#92;&quot;sep&#92;&quot;:&#92;&quot;,&#92;&quot;,&#92;&quot;hdrin&#92;&quot;:true,&#92;&quot;hdrout&#92;&quot;:&#92;&quot;once&#92;&quot;,&#92;&quot;multi&#92;&quot;:&#92;&quot;one&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;r&#92;&quot;,&#92;&quot;temp&#92;&quot;:&#92;&quot;timestamp,temperature&#92;&quot;,&#92;&quot;skip&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;strings&#92;&quot;:true,&#92;&quot;include_empty_strings&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;include_null_values&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a5c5746934670306&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4aff5b57cbb63b8f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Daily PLC Logger&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// @ts-ignore Node ≥ 18.15 provides fs.statfsSync; editor types may lag&#92;&#92;n&#92;&#92;nconst now = new Date();&#92;&#92;nconst dateStr = now.toISOString().split(&#39;T&#39;)[0];&#92;&#92;nconst timestamp = now.toISOString();&#92;&#92;n&#92;&#92;nconst filename = `./plc_data_${dateStr}.csv`;&#92;&#92;n&#92;&#92;nmsg.payload = {&#92;&#92;n    timestamp: timestamp,&#92;&#92;n    temperature: msg.payload,&#92;&#92;n};&#92;&#92;n&#92;&#92;nmsg.filename = filename;&#92;&#92;n&#92;&#92;n// Track last date in flow context&#92;&#92;nconst lastDate = flow.get(&#39;lastDate&#39;) || &#39;&#39;;&#92;&#92;nif (lastDate !== dateStr) {&#92;&#92;n    msg.reset = true; // Will trigger CSV node to write headers&#92;&#92;n    flow.set(&#39;lastDate&#39;, dateStr);&#92;&#92;n} &#92;&#92;n&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac0d35a6466cfcb4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5c5746934670306&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Log Data to CSV file&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:true,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2518dc909d447655&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d796d3aee8ea0343&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;read&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4aff5b57cbb63b8f&#92;&quot;],[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;23ebc0da4315ac46&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;ns=3;i=1004&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d796d3aee8ea0343&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;181ed86f9c11d1f7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scope&#92;&quot;:[&#92;&quot;a5c5746934670306&#92;&quot;],&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b34d440897108110&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b34d440897108110&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errrors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;575ed67714072973&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Check Disk Space&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;try {&#92;&#92;n    // Get disk usage information&#92;&#92;n    const stats = fs.statfsSync(&#39;./&#39;);&#92;&#92;n&#92;&#92;n    const totalSpace = stats.blocks * stats.bsize;&#92;&#92;n    const freeSpace = stats.bfree * stats.bsize;&#92;&#92;n    const usedSpace = totalSpace - freeSpace;&#92;&#92;n    const percentUsed = (usedSpace / totalSpace) * 100;&#92;&#92;n&#92;&#92;n    msg.payload = {&#92;&#92;n        totalGB: (totalSpace / (1024 ** 3)).toFixed(2),&#92;&#92;n        freeGB: (freeSpace / (1024 ** 3)).toFixed(2),&#92;&#92;n        usedGB: (usedSpace / (1024 ** 3)).toFixed(2),&#92;&#92;n        percentUsed: percentUsed.toFixed(2)&#92;&#92;n    };&#92;&#92;n&#92;&#92;n    // Warning threshold&#92;&#92;n    if (percentUsed &amp;gt; 90) {&#92;&#92;n        msg.warning = `Disk space critical: ${percentUsed.toFixed(1)}% used`;&#92;&#92;n    }&#92;&#92;n&#92;&#92;n    return msg;&#92;&#92;n&#92;&#92;n} catch (err) {&#92;&#92;n    msg.payload = { error: err.message };&#92;&#92;n    return msg;&#92;&#92;n}&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[{&#92;&quot;var&#92;&quot;:&#92;&quot;fs&#92;&quot;,&#92;&quot;module&#92;&quot;:&#92;&quot;fs&#92;&quot;}],&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e719ae6fee22c812&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d08353a9c90b0396&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1800&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;575ed67714072973&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e719ae6fee22c812&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Disk Full Warning !&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2518dc909d447655&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;66776385db5794bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7131c5523d86fe8b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;node-red-contrib-opcua&#92;&quot;:&#92;&quot;0.2.342&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow248.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-248&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/how-to-log-plc-data-csv-files/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;talk to our team&lt;/a&gt;, they’ll walk you through a live demo showing how FlowFuse helps you connect, collect, transform, and visualize your industrial data reliably and intelligently.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/introducing-flowfuse-expert/</id>
        <title>Introducing FlowFuse Expert</title>
        <summary>Your AI expert for FlowFuse and Node-RED</summary>
        <updated>2025-10-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/introducing-flowfuse-expert/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;We&#39;ve had an exciting week launching MCP and ONNX nodes, and now we’ve added something else we&#39;re really excited about: &lt;strong&gt;FlowFuse Expert&lt;/strong&gt;. It helps you build flows by providing a step-by-step recipe to build an application in FlowFuse and Node-RED, in plain language.&lt;/p&gt;
&lt;p&gt;Oh, and it was created by and is running on FlowFuse technology! Take a look:&lt;/p&gt;
&lt;p&gt;Instead of hunting through documentation or piecing together forum posts, you simply describe what you want to build and get a clear recipe for creating it.&lt;/p&gt;
&lt;p&gt;Head over to &lt;a href=&quot;https://flowfuse.com/&quot;&gt;flowfuse.com&lt;/a&gt; and you&#39;ll see it right on the home page. Type what you&#39;re trying to build. FlowFuse Expert might ask a few questions to clarify your setup, and once you answer, it will provide a simple, easy-to-follow recipe: which nodes you need with exact copyable names, how to configure them, and how to wire them together.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert: Providing Recipe for Connecting Serial Devices&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-expert.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert: Providing a Recipe for Connecting Serial Devices&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Down the road, we plan to integrate it directly into the FlowFuse environment. So if you&#39;re already using &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert&lt;/a&gt; to speed up your development, FlowFuse Expert will be right there alongside it, answering questions and providing recipes for whatever you&#39;re trying to build.&lt;/p&gt;
&lt;h2 id=&quot;why-we-built-this&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/introducing-flowfuse-expert/#why-we-built-this&quot;&gt;Why We Built This&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We kept seeing people get stuck at the same point. They were excited about FlowFuse and Node-RED, with a clear idea of what they wanted to build, but weren&#39;t sure how to get started.&lt;/p&gt;
&lt;p&gt;That gap between vision and implementation shouldn&#39;t be a bottleneck, nor should time be wasted reading long documents or articles. FlowFuse Expert provides the starting point, the specific guidance you need to start building, without dumbing anything down.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/introducing-flowfuse-expert/#how-it-works&quot;&gt;How It Works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Expert is built on and runs entirely using FlowFuse technology itself. It is powered by RAG + GPT-4.1. We&#39;ve ingested all of our blogs, changelogs, and documentation into a vector database. When you describe what you want to build, FlowFuse Expert searches this knowledge base and uses that context to generate accurate, and super simple step-by-step instructions.&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/introducing-flowfuse-expert/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Expert is just one of the many powerful tools we’ve made available to everyone. With FlowFuse, you can deploy, scale, and manage Node-RED effortlessly, accelerate development with FlowFuse AI-assistance, and build your own MCP server. Let AI agents monitor and control industrial applications using MCP nodes—or run your custom AI models in Node-RED with ONNX nodes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start your free FlowFuse trial today&lt;/a&gt; and see how you can deploy, manage, and scale secure Node-RED to build powerful industrial applications while exploring the new AI tools we’ve made available for FlowFuse users within Platform.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/</id>
        <title>Building MCP Servers for AI Agent Integration in Node-RED with FlowFuse</title>
        <summary>Integrate AI into industrial systems FlowFuse new MCP nodes</summary>
        <updated>2025-10-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse released MCP nodes for Node-RED, allowing AI to directly interact with the flows you have built. These nodes let AI read sensor data, query databases, and control equipment. You use FlowFuse to collect and manage data in your flows, while AI agents determines what actions to take and why, enabling intelligent monitoring and automated control of factory and IIoT/IoT systems.&lt;/p&gt;
&lt;p&gt;This article explains how to build an MCP server with FlowFuse and connect AI to your systems for real-time insights, operational decisions, and automated control.&lt;/p&gt;
&lt;h3 id=&quot;what-is-mcp%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#what-is-mcp%3F&quot;&gt;What Is MCP?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Model Context Protocol (MCP) is an open standard that enables AI assistants to access data and execute actions across external systems.&lt;/p&gt;
&lt;p&gt;MCP works through three key components. Resources give AI visibility into your operations through read-only access to sensor data, database records, SCADA tags, and equipment logs. This real-time information helps AI understand what&#39;s actually happening on your factory floor or in your IIoT environment.&lt;/p&gt;
&lt;p&gt;Tools let AI perform specific actions in your systems. These might include adjusting equipment parameters, triggering maintenance alerts, or generating operational reports. Each tool clearly defines what it needs as input and what it will produce as output, which keeps operations predictable and safe.&lt;/p&gt;
&lt;p&gt;Prompts are workflow templates that guide AI through more complex tasks. They show AI how to use multiple resources and tools together to complete multi-step operations. This is particularly valuable when you need AI to follow established procedures rather than improvising solutions.&lt;/p&gt;
&lt;p&gt;When you connect an AI agent to your MCP server, it discovers all available resources and tools automatically. The protocol handles the technical details of data requests and action execution, so AI can start working with your industrial systems right away. You build your flows in Node-RED, and AI learns how to interact with them intelligently through the MCP interface.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section guides you through setting up an MCP server, defining resources, and creating tools so AI can interact with your system.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A running FlowFuse Enterprise instance.&lt;/strong&gt; If you do not have one, &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact us&lt;/a&gt; to discuss Enterprise options and get started.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ensure the &lt;code&gt;@flowfuse-nodes/nr-mcp-server-nodes&lt;/code&gt; package is installed&lt;/strong&gt;. This will add the &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mcp/&quot;&gt;MCP nodes&lt;/a&gt; to your Node palette in your instance editor.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The MCP nodes (@flowfuse-nodes/nr-mcp-server-nodes) are only available on the Enterprise tier.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;configuring-the-mcp-server&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#configuring-the-mcp-server&quot;&gt;Configuring the MCP Server&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before defining resources or tools, the MCP Server must be configured. This server acts as the central endpoint for AI agents, ensuring all resources and tools are accessible under a single, consistent configuration.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;MCP Resource or Tool&lt;/strong&gt; node onto your workspace and click the &lt;strong&gt;+&lt;/strong&gt; next to Server to create a new configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define the server properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: Enter a descriptive name, e.g., &lt;code&gt;Node-RED MCP Server&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol&lt;/strong&gt;: Leave the default &lt;code&gt;http/sse&lt;/code&gt; (currently the only option).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path&lt;/strong&gt;: Specify the endpoint path for the server, e.g., &lt;code&gt;/mcp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MCP Server Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-server-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Caption: Configuring the MCP Server in Node-RED&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Click Done&lt;/strong&gt; to save the server configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the server is configured, clients can connect using a URL. The URL to connect with is your instance URL plus the MCP path you configured, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://your-instance.flowfuse.cloud/mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or if you are running FlowFuse Node-RED instance locally, use the host, port, and MCP path of your instance, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:1880/mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://192.168.1.100:1880/mcp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This URL allows AI agents to discover resources, execute tools, and interact with your flows.&lt;/p&gt;
&lt;h3 id=&quot;securing-your-mcp-server&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#securing-your-mcp-server&quot;&gt;Securing Your MCP Server&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To ensure your MCP server is protected from unauthorized access, enable FlowFuse User Authentication.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your instance &lt;strong&gt;Settings → Security&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;FlowFuse User Authentication&lt;/strong&gt;, click &lt;strong&gt;Save Changes&lt;/strong&gt;, and in the popup, click &lt;strong&gt;Restart&lt;/strong&gt; to apply the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse User Authentication settings screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-auth.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse User Authentication settings screenshot&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add Token&lt;/strong&gt; and provide a descriptive name for identification&lt;/li&gt;
&lt;li&gt;Set an expiry date (recommended for enhanced security)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt; and copy the generated token&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When connecting to your MCP server from a client, include the token in the request headers:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-154&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-154&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;node-red-mcp-server&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://localhost:1880/mcp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;headers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bearer ffhttp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-154&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;ffhttp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;/code&gt; with your actual token. This ensures that only authorized clients can access your MCP server resources and tools.&lt;/p&gt;
&lt;div class=&quot;blog-update-notes&quot;&gt;
    &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/blog/2025/12/flowfuse-release-2-25/#interact-with-mcp-resources-in-flowfuse-expert&quot;&gt;FlowFuse Expert now allows you to connect directly with your MCP Resources and Tools&lt;/a&gt;, so you don&#39;t need to connect external AI agents anymore.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;You&#39;ll need to select the MCP server you want to connect to in the FlowFuse Expert Insights tab. Once connected, FlowFuse Expert will automatically query your Resources and execute your Tools based on your team role and your instructions. The annotations you configure in the &lt;a href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#defining-an-mcp-tool&quot;&gt;MCP Tool node&lt;/a&gt; (read-only, destructive, idempotent, open-world) integrate with FlowFuse&#39;s role-based access control to ensure secure, appropriate access for every team member.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-in-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;defining-an-mcp-resource&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#defining-an-mcp-resource&quot;&gt;Defining an MCP Resource&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now let&#39;s start by defining a Resource. In MCP, a Resource represents a data source that you want to expose to an AI agent. In an industrial context, this could be a sensor value, a machine&#39;s status, or a list of production lines.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the MCP Resource node from the palette onto your workspace.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration panel and select the added mcp server configuration.&lt;/li&gt;
&lt;li&gt;Enter the unique id for the resource, for example : &amp;quot;all-production-lines&amp;quot;&lt;/li&gt;
&lt;li&gt;Provide a unique URI for this specific resource, for example, &lt;code&gt;mcp://monitor-all-production-lines&lt;/code&gt; Make sure your every resource must have a unique URI.&lt;/li&gt;
&lt;li&gt;Enter a clear, human-readable title, like &amp;quot;Monitoring All production lines&amp;quot;. This is the name the AI agent or client that will connect will see, so make it descriptive.&lt;/li&gt;
&lt;li&gt;Give the node a descriptive name for your flow, such as Production Lines Resource, and enter a brief description.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MCP Resource Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-resource-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Setting up an MCP Resource in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click Done and then Deploy your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point, your MCP server is live and resource is discoverable. However, it doesn&#39;t contain any data yet.&lt;/p&gt;
&lt;p&gt;To expose data you will need to connect the MCP Resource node to any data-producing node in your flow. This could be an HTTP Request node retrieving data from an API, a FlowFuse Query node for fetching records from a FlowFuse data table, industrial connectors such as OPC UA Read, Modbus Read, PLC Read nodes.&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Next, drag the MCP Response node and connect its input to the output of the upstream data source node.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;The MCP Response node is crucial because it delivers the results of your flow back to the AI agent. Without it, the AI will not receive the data it requests. Any errors are also fed back to the MCP Response node, enabling the AI to handle them appropriately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;Deploy the flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, when an AI agent or any other client requests this URI, the flow will automatically execute and query your data source for the latest information. This data is then returned to the agent, providing it with the real-time context needed to answer your questions.&lt;/p&gt;
&lt;h4 id=&quot;example%3A-monitoring-production-lines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#example%3A-monitoring-production-lines&quot;&gt;Example: Monitoring Production Lines&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For this article, we&#39;ve built a demonstration data flow. We have a table named production-lines where new data is inserted every five seconds from 10 different lines.&lt;/p&gt;
&lt;p&gt;We then created a data resource and exposed all the line data to it. Now, let&#39;s connect a AI Agent to this resource and explore the kinds of questions we can ask to monitor the factory floor effectively.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Monitoring Production Lines&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/resource-demo.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Production line monitoring using MCP Resources&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;defining-an-mcp-tool&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#defining-an-mcp-tool&quot;&gt;Defining an MCP Tool&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While resources are useful for providing access to data, tools enable an AI agent to perform specific, parameterized actions within your system.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the MCP Tool node from the Node-RED palette onto your workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open the configuration panel and select the MCP Server configuration you previously created.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter a tool name that will be visible to clients connecting to the MCP server, such as &lt;em&gt;Maintenance&lt;/em&gt; or &lt;em&gt;Maintenance Scheduler&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, set annotations. Annotations help AI clients understand your tool&#39;s behavior and control which FlowFuse team members can access it based on their role (Viewer, Member, or Owner).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read-Only Hint&lt;/strong&gt;: Tool only reads data, doesn&#39;t modify anything. Safe for exploratory queries.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access&lt;/strong&gt;: Viewer role and above&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Destructive Hint&lt;/strong&gt;: Tool may delete or irreversibly modify data. Use with caution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access&lt;/strong&gt;: Owner role only&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Idempotent Hint&lt;/strong&gt;: Calling the tool multiple times with same parameters has the same effect as calling it once. Safe to retry.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access&lt;/strong&gt;: No effect on roles (only relevant for writing tools, which require Member minimum)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open-World Hint&lt;/strong&gt;: Tool interacts with external systems or data sources that may change unpredictably.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access&lt;/strong&gt;: Member role and above&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These are hints only and do not enforce behavior. The actual behavior of a tool is determined by your Node-RED flow implementation. Annotations are used by FlowFuse for role-based access control (RBAC) and FlowFuse Expert. They are also part of the standard MCP specification and can be consumed by external agents, but their effect ultimately depends on the client&#39;s implementation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide a clear description of the tool&#39;s purpose, and assign a descriptive name to the node within your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define the input schema in JSON format. This schema helps the AI understand what data is required to perform the action and also validates incoming requests. For detailed guidance, refer to the &lt;a href=&quot;https://json-schema.org/learn/getting-started-step-by-step&quot;&gt;Getting Started Guide&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: You can also use the FlowFuse Expert to generate the JSON schema automatically. Just click &lt;strong&gt;Ask FlowFuse Expert&lt;/strong&gt; in the input schema field and describe the expected input in plain English.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below is an example schema for a Tool node. It shows how data is defined, its type, and which fields are required along with minimum lengths:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-353&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-353&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;line&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The production line where maintenance is required&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;minLength&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Description of the maintenance task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;minLength&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;priority&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Priority of the task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;Low&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;Medium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;High&quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;line&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;priority&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-353&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MCP Tool Node Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mcp-tools.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Setting up an MCP Tool in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;em&gt;Done&lt;/em&gt;, then deploy your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this stage, the tool becomes discoverable by connected AI clients. However, it will not perform any action until it is linked to a flow that executes a task, such as an HTTP Request node performing a POST operation, a Query node inserting data into a database, or an OPC UA Write node controlling a device.&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag the MCP Response node and connect its input to the output of the final node in your action flow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The MCP Response node is necessary because the AI needs to receive the outcome of the action—whether it was successful or not. Errors are also fed back to the MCP Response node, enabling the AI to handle them appropriately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow once again.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your MCP Tool is now active. When an AI agent invokes it, the connected flow executes the defined action and returns the result to the agent.&lt;/p&gt;
&lt;h4 id=&quot;example%3A-scheduling-maintenance-for-production-lines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#example%3A-scheduling-maintenance-for-production-lines&quot;&gt;Example: Scheduling Maintenance for Production Lines&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this example, the flow includes a tool that triggers a POST request to the maintenance system API, which was developed using FlowFuse and the FlowFuse Dashboard. The AI Assistant was then asked to identify which production line was performing the worst and schedule a maintenance task for it.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Scheduling Maintenance Example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tools-demo.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;AI agent scheduling maintenance using an MCP Tool&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is the flow that includes the Resource we created to monitor production lines and the Tool that sends a POST request.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The flow uses the FlowFuse Query node and FlowFuse tables, which are only available on the Enterprise tier. If you do not have Enterprise, you can use other data sources instead, such as HTTP Request, OPC UA, or other database nodes.&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-247&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow247 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c0952d97df3a1491&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;2da059f0b9465120&#92;&quot;,&#92;&quot;5ee2cab1a6affc67&#92;&quot;,&#92;&quot;1ea311e63b6b7b89&#92;&quot;,&#92;&quot;628139fa99072e2e&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:712,&#92;&quot;h&#92;&quot;:142},{&#92;&quot;id&#92;&quot;:&#92;&quot;2da059f0b9465120&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mcp-response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0952d97df3a1491&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5ee2cab1a6affc67&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mcp-resource&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0952d97df3a1491&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Lines MCP Resource&#92;&quot;,&#92;&quot;server&#92;&quot;:&#92;&quot;460154892784fd4e&#92;&quot;,&#92;&quot;resourceUri&#92;&quot;:&#92;&quot;mcp://monitor-all-production-lines&#92;&quot;,&#92;&quot;resourceId&#92;&quot;:&#92;&quot;all-production-lines&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Monitoring All Production lines&#92;&quot;,&#92;&quot;description&#92;&quot;:&#92;&quot;Represents the real-time data stream for all production Line. Contains sensor readings, operational status, and performance metrics accessible via the MCP server.&#92;&quot;,&#92;&quot;mimeType&#92;&quot;:&#92;&quot;application/json&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1ea311e63b6b7b89&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1ea311e63b6b7b89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0952d97df3a1491&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retrieve Lines Data&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;SELECT * FROM public.production_lines;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2da059f0b9465120&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;628139fa99072e2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0952d97df3a1491&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Catch errors in this group&#92;&quot;,&#92;&quot;scope&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2da059f0b9465120&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;460154892784fd4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mcp-server&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;NODE-RED MCP SERVER&#92;&quot;,&#92;&quot;protocol&#92;&quot;:&#92;&quot;http&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/mcp&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;a55471a9a3c7af9f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;7fd32aa0ef7ca984&#92;&quot;,&#92;&quot;a412bb732aa5e5e0&#92;&quot;,&#92;&quot;3b3c8c52146e69ef&#92;&quot;,&#92;&quot;03a75b77302b1d19&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:339,&#92;&quot;w&#92;&quot;:712,&#92;&quot;h&#92;&quot;:142},{&#92;&quot;id&#92;&quot;:&#92;&quot;7fd32aa0ef7ca984&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a55471a9a3c7af9f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Schedule Maintenance&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;POST&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3b3c8c52146e69ef&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a412bb732aa5e5e0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mcp-tool&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a55471a9a3c7af9f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;server&#92;&quot;:&#92;&quot;460154892784fd4e&#92;&quot;,&#92;&quot;toolName&#92;&quot;:&#92;&quot;maintenance&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Create Maintenance Task&#92;&quot;,&#92;&quot;description&#92;&quot;:&#92;&quot;Handles maintenance tasks on the production line&#92;&quot;,&#92;&quot;inputSchema&#92;&quot;:&#92;&quot;{&#92;&#92;n  &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;object&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;properties&#92;&#92;&#92;&quot;: {&#92;&#92;n    &#92;&#92;&#92;&quot;line&#92;&#92;&#92;&quot;: {&#92;&#92;n      &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;The production line where maintenance is required&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;minLength&#92;&#92;&#92;&quot;: 1&#92;&#92;n    },&#92;&#92;n    &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: {&#92;&#92;n      &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Description of the maintenance task&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;minLength&#92;&#92;&#92;&quot;: 1&#92;&#92;n    },&#92;&#92;n    &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot;: {&#92;&#92;n      &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;string&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Priority of the task&#92;&#92;&#92;&quot;,&#92;&#92;n      &#92;&#92;&#92;&quot;enum&#92;&#92;&#92;&quot;: [&#92;&#92;n        &#92;&#92;&#92;&quot;Low&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;Medium&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;High&#92;&#92;&#92;&quot;&#92;&#92;n      ]&#92;&#92;n    }&#92;&#92;n  },&#92;&#92;n  &#92;&#92;&#92;&quot;required&#92;&#92;&#92;&quot;: [&#92;&#92;n    &#92;&#92;&#92;&quot;line&#92;&#92;&#92;&quot;,&#92;&#92;n    &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;,&#92;&#92;n    &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot;&#92;&#92;n  ]&#92;&#92;n}&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7fd32aa0ef7ca984&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3b3c8c52146e69ef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mcp-response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a55471a9a3c7af9f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;03a75b77302b1d19&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;3831e63ae3acc9b0&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a55471a9a3c7af9f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Catch errors in this group&#92;&quot;,&#92;&quot;scope&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3b3c8c52146e69ef&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4e9c50c5940103ab&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse-nodes/nr-mcp-server-nodes&#92;&quot;:&#92;&quot;0.1.1&#92;&quot;,&#92;&quot;@flowfuse/nr-tables-nodes&#92;&quot;:&#92;&quot;0.1.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow247.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-247&#39;) })&lt;/script&gt;
&lt;p&gt;If you need more example flows, you can import the examples that come with the MCP nodes. Click the main menu from the top right, click Import, switch to Examples, and look for &lt;code&gt;@flowfuse-nodes/nr-mcp-server-node&lt;/code&gt;, then select mcp_server and click Import. If you prefer a video tutorial, watch this &lt;a href=&quot;https://www.youtube.com/watch?v=troUvaF8V68&quot;&gt;video tutorial on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With your MCP server, Resources, and Tools in place, the AI agent can now interact with your industrial systems in a structured way. Up to this point, we&#39;ve covered the basics and demonstrated a simple workflow. The MCP Prompt node, which allows AI agents to be guided through complex, multi-step tasks, will be explored in a future article.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/building-mcp-server-using-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide demonstrated how to build a fully functional MCP server with FlowFuse and Node-RED, providing AI agents with structured access to industrial systems through Resources and Tools, which enable workflows such as monitoring production lines, scheduling maintenance, and automating operational decisions — all without complex coding.&lt;/p&gt;
&lt;p&gt;FlowFuse &lt;a href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/&quot;&gt;recently added ONNX AI nodes&lt;/a&gt;. With these nodes, you can train custom models, deploy them in Node-RED, and execute tasks tailored to your processes. Combined with FlowFuse’s capabilities to collect, transform, and visualize industrial data, the platform makes development, monitoring, and optimization faster, smarter, and more scalable.&lt;/p&gt;
&lt;p&gt;Adopting MCP with FlowFuse is a strategic step toward AI-enabled, future-ready industrial automation. &lt;a href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/&quot;&gt;Book a demo today&lt;/a&gt; to see how FlowFuse connects, transforms, and visualizes your industrial data while making AI-driven operations easy and actionable.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/ai-on-flowfuse/</id>
        <title>MCP and Custom AI Models on FlowFuse!</title>
        <summary>Create your own AI agents and deploy trained models in Node-RED</summary>
        <updated>2025-10-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/ai-on-flowfuse/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;We have a VERY exciting announcement today: you can now build an MCP server and upload custom-trained AI models to FlowFuse!&lt;/p&gt;
&lt;h2 id=&quot;ai-on-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/#ai-on-flowfuse&quot;&gt;AI on FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is already the most capable and flexible low-code development environment out there. FlowFuse makes it secure, robust, and scalable.&lt;/p&gt;
&lt;p&gt;As of today, you can now use FlowFuse to create your own MCP server and use custom-trained AI models that you&#39;ve built for any application.&lt;/p&gt;
&lt;p&gt;Build an MCP server to create an AI agent that will do whatever you&#39;ve design it to do. And add a training model that you&#39;ve built using your own training data, so data processing works exactly the way you want it to.&lt;/p&gt;
&lt;h2 id=&quot;model-context-protocol&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/#model-context-protocol&quot;&gt;Model Context Protocol&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LLMs were trained by scraping data from the internet to build data models that can complete a task (like answering a question or writing a blog article -- but not this one!) given some input prompt. When you rely on an LLM to answer questions that are very general or perform operations that are rather straightforward, LLMs can generally do so with ease.&lt;/p&gt;
&lt;p&gt;However, if you want to do something more sophisticated, or create an AI agent that will rely on specific data, that data needs to be presented to the AI somehow. MCP is what enables that.&lt;/p&gt;
&lt;p&gt;Instead of relying just on LLMs trained from scraping the entire internet, the new MCP nodes enable you to create your own MCP servers, so you can present information to an AI tool, putting much more power and control in your hands as a developer.&lt;/p&gt;
&lt;p&gt;You are now able to create your own, custom AI agent using FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;custom-data-models&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/#custom-data-models&quot;&gt;Custom Data Models&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When creating an AI agent or getting AI assistance with some task, one component is the data that is surfaced to the model. That part is handled by MCP. Another part is how the model interacts with that data. That part is handled with our new AI nodes.&lt;/p&gt;
&lt;p&gt;Instead of relying on a standard LLM, even one that has been set up to connect with an MCP server, it is possible to train the model itself. The new AI nodes allow you to train a custom model, put it in &lt;a href=&quot;https://onnx.ai/&quot;&gt;ONNX&lt;/a&gt; format, and connect it to Node-RED, where it can be deployed to run any operation you wish with your new, personally-trained AI.&lt;/p&gt;
&lt;h2 id=&quot;the-sky-is-the-limit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/#the-sky-is-the-limit&quot;&gt;The Sky Is the Limit&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The flexibility of Node-RED, the reliability of FlowFuse, and the customizability enabled by these MCP and AI nodes means you can build just about any AI application you wish!&lt;/p&gt;
&lt;p&gt;And this week, we&#39;re going to tell you all about it. Stay tuned for a demo or three, some tutorials, and overall plenty of instructional content goodness that will demonstrate the power that is now available with these AI releases!&lt;/p&gt;
&lt;p&gt;While we&#39;re at it, we are also going to unveil a new feature right on our home page: a trained FlowFuse Expert (AI) that will teach you how to build applications in FlowFuse and Node-RED!&lt;/p&gt;
&lt;h2 id=&quot;try-it-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/ai-on-flowfuse/#try-it-now&quot;&gt;Try it Now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ready to try out these new nodes? If you&#39;re new to FlowFuse, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;create a trial team&lt;/a&gt;. Then, head to Manage Palette (in the hamburger menu on the right side of the Node-RED editor), click Install, and in the dropdown menu, choose FlowFuse Nodes to see the catalog of nodes that are exclusive to FlowFuse customers. From here, you can install both the MCP nodes and AI ONNX nodes.&lt;/p&gt;
&lt;p&gt;If you&#39;re an existing FlowFuse user, begin by restarting the Node-RED instance where you want to use the nodes, then follow the same instructions as above.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/</id>
        <title>EtherNet/IP Integration with FlowFuse: Communicating with Allen-Bradley PLCs</title>
        <summary>A guide to connected and unconnected EtherNet/IP communication with FlowFuse</summary>
        <updated>2025-10-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;EtherNet/IP is one of the most widely used industrial communication protocols for connecting PLCs, sensors, and controllers across manufacturing environments. If you&#39;re working with Allen-Bradley PLCs—whether it&#39;s ControlLogix, CompactLogix, or MicroLogix—you&#39;re using some of the most trusted automation hardware in the industry.&lt;/p&gt;
&lt;p&gt;This guide will show you how to integrate Allen-Bradley PLCs with FlowFuse using EtherNet/IP. While the focus is on Allen-Bradley, the same Node-RED nodes and techniques also work with other EtherNet/IP-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.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before integrating your Allen-Bradley PLC with FlowFuse, ensure you have the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PLC Configuration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your Allen-Bradley PLC (ControlLogix, CompactLogix, or MicroLogix) should be properly configured and operational.&lt;/li&gt;
&lt;li&gt;Ensure that the appropriate ladder logic program is written according to your requirements and successfully downloaded to the PLC.&lt;/li&gt;
&lt;li&gt;Verify that the controller tags or data structures you want to access are properly defined.&lt;/li&gt;
&lt;li&gt;Note the PLC&#39;s IP address and slot number (typically slot 0 for the processor).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Node-RED:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt; to install Node-RED on your edge device.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why FlowFuse Device Agent?&lt;/strong&gt; 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. &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Sign up for free&lt;/a&gt; to get started.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Network Setup:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that the device running Node-RED is on the same network as the PLC and can successfully ping the PLC&#39;s IP address.&lt;/li&gt;
&lt;li&gt;Ensure the PLC is properly connected to the network via Ethernet with a static IP address configured.&lt;/li&gt;
&lt;li&gt;Ensure that firewalls do not block EtherNet/IP communication (typically port 44818 for both TCP and UDP).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;understanding-ethernet%2Fip-communication-modes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#understanding-ethernet%2Fip-communication-modes&quot;&gt;Understanding EtherNet/IP Communication Modes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;EtherNet/IP 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.&lt;/p&gt;
&lt;p&gt;EtherNet/IP supports two primary communication modes: &lt;strong&gt;connected&lt;/strong&gt; and &lt;strong&gt;unconnected&lt;/strong&gt; 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.&lt;/p&gt;
&lt;h3 id=&quot;connected-messaging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#connected-messaging&quot;&gt;Connected Messaging&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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&#39;s limited connection slots, typically ranging from 8 to 32 depending on the model.&lt;/p&gt;
&lt;p&gt;Connected messaging itself can operate in two ways:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Without Routing (Direct Connection):&lt;/strong&gt;
Used for PLCs that connect directly via Ethernet without backplane routing, such as the Allen-Bradley Micro800/850/870 series. Only the IP address is needed—no slot number or routing path is required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With Routing:&lt;/strong&gt;
Used 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.&lt;/p&gt;
&lt;h3 id=&quot;unconnected-messaging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#unconnected-messaging&quot;&gt;Unconnected Messaging&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unconnected messaging sends individual requests without maintaining a persistent connection. Each transaction is standalone—request, response, done.&lt;/p&gt;
&lt;p&gt;This approach doesn&#39;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.&lt;/p&gt;
&lt;p&gt;In practice, use connected mode for frequent polling and unconnected mode for occasional reads or writes—but always check your PLC&#39;s documentation to confirm which modes are supported.&lt;/p&gt;
&lt;h2 id=&quot;installing-the-ethernet%2Fip-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#installing-the-ethernet%2Fip-node&quot;&gt;Installing the EtherNet/IP Node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open your FlowFuse Instance Node-RED editor in a web browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the main menu (three horizontal lines) in the top-right corner.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &amp;quot;Manage Palette&amp;quot; from the menu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to the &amp;quot;Install&amp;quot; tab and search for &lt;code&gt;node-red-contrib-cip-ethernet-ip&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;quot;Install&amp;quot; next to the node name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait for the installation to complete.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you&#39;ll find the EtherNet/IP nodes in your palette under the &amp;quot;plc&amp;quot; category. The main nodes are &lt;code&gt;ethernet-ip in&lt;/code&gt; for reading data and &lt;code&gt;ethernet-ip out&lt;/code&gt; for writing data to the PLC.&lt;/p&gt;
&lt;h2 id=&quot;configuring-the-ethernet%2Fip-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#configuring-the-ethernet%2Fip-node&quot;&gt;Configuring the EtherNet/IP Node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you have installed the EtherNet/IP node, it is time to configure the connection to your Allen-Bradley PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag any EtherNet/IP node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open its configuration panel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &amp;quot;+&amp;quot; icon next to the &lt;strong&gt;&amp;quot;PLC&amp;quot;&lt;/strong&gt; dropdown to add a new PLC configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the basic connection details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Give your connection a descriptive name, such as &lt;strong&gt;&amp;quot;Line 1 PLC&amp;quot;&lt;/strong&gt;, for easy identification.&lt;/li&gt;
&lt;li&gt;Enter your PLC’s &lt;strong&gt;IP address&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Specify the &lt;strong&gt;slot number&lt;/strong&gt; where your processor is located.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the communication parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cycle time&lt;/strong&gt; controls how often the node communicates with the PLC (for example, 500 ms means it updates twice per second).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the communication mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Standard (Unconnected)&lt;/strong&gt; — This is the default option supported by most PLCs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connected (With Routing)&lt;/strong&gt; — Use this option if you want to enable connected messaging with routing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;EtherNet/IP Node Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/eth-ip-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;EtherNet/IP Node Configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This node does not currently support connected messaging (without routing). I have developed node — &lt;code&gt;@sumit_shinde_84/node-red-contrib-cip-ethernet-ip-enhanced&lt;/code&gt; — which supports connected messaging (without routing) but is still under development.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;adding-tags-to-read-or-write&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#adding-tags-to-read-or-write&quot;&gt;Adding Tags to Read or Write&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After configuring the endpoint, you need to specify which tags you want to read from or write to the PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the same configuration window, switch to the &amp;quot;Tags&amp;quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &amp;quot;+Add&amp;quot; button in the top-right corner to add a new tag.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the tag details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: Enter the exact tag name as it appears in your PLC program (e.g., &amp;quot;Motor1Speed&amp;quot; or &amp;quot;Program:MainProgram.Motor1Speed&amp;quot;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type&lt;/strong&gt;: Select the data type from the dropdown (e.g., BOOL, INT, DINT, REAL, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding tags to read and write&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/adding-tags.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding tags to read and write&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Once you&#39;ve added all your tags, click &amp;quot;Add&amp;quot; to save the configuration, then &amp;quot;Done&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, deploy the flow by clicking the &amp;quot;Deploy&amp;quot; button in the top-right corner.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start, I&#39;d like to show you what I&#39;ve prepared—a flow where I&#39;m sending commands to the PLC to control the stack light. To interact with it, I&#39;ve built a nice dashboard using &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt;. Here&#39;s a quick demonstration:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;6X9HXJLKPyo&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;That’s the program I have downloaded to the PLC&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Program downloaded to the PLC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/plc-program.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Program downloaded to the PLC&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now let’s learn how to build a flow that can both read and write data to your PLC.&lt;/p&gt;
&lt;h3 id=&quot;writing-data-to-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#writing-data-to-your-plc&quot;&gt;Writing Data to Your PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;&lt;code&gt;ethernet-ip out&lt;/code&gt;&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open its configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the PLC configuration you created earlier from the dropdown.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the scope under which you added the tag, choose the tag that you want to write to.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the EtherNet/IP out node to write data to a PLC tag&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/eth-out-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the EtherNet/IP out node to write data to a PLC tag&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;quot;Done&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect an &lt;strong&gt;&lt;code&gt;inject&lt;/code&gt;&lt;/strong&gt; node or any other input node to send data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click inject button to test it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;reading-single-tag-from-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#reading-single-tag-from-your-plc&quot;&gt;Reading Single Tag from Your PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reading data from your PLC is the foundation of any monitoring or control system. Whether you&#39;re tracking production counts, monitoring temperatures, or checking machine status, you&#39;ll start here.&lt;/p&gt;
&lt;p&gt;Here&#39;s how to set it up:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;&lt;code&gt;ethernet-ip in&lt;/code&gt;&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open its configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the PLC configuration you created earlier from the dropdown.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the scope under which you added the tag, select the mode to &amp;quot;Single Tag&amp;quot; and choose the tag that you want to read.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the EtherNet/IP in node to read a single tag from the PLC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/read-plc-tag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the EtherNet/IP in node to read a single tag from the PLC&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;quot;Done&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect a &lt;strong&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/strong&gt; node to view the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The node will automatically read data based on your configured cycle time and output it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Reading single tags individually isn&#39;t recommended for production use as it creates unnecessary network overhead. Consider using &amp;quot;All tags&amp;quot; mode or structuring your PLC with array data types to read multiple values efficiently in one request.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;reading-multiple-tags-from-your-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#reading-multiple-tags-from-your-plc&quot;&gt;Reading Multiple Tags from Your PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Let me show you how:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;&lt;code&gt;ethernet-ip in&lt;/code&gt;&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open its configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the PLC configuration you created earlier from the dropdown.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Mode&lt;/strong&gt; field, select &lt;strong&gt;&amp;quot;All tags&amp;quot;&lt;/strong&gt; to read all configured tags together in a single message, or select &lt;strong&gt;&amp;quot;All tags (one per msg)&amp;quot;&lt;/strong&gt; if you want each tag value sent as a separate message.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Reading all tags with each tag sent as a separate message&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/all-tags-one-msg-per-tag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Reading all tags with each tag sent as a separate message&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Reading all tags together in a single message object&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/all-tags-single-obj.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Reading all tags together in a single message object&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click &amp;quot;Done&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect a &lt;strong&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/strong&gt; node to view the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The node will automatically read all configured tags based on your cycle time, giving you full visibility into your PLC data.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;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.&lt;/p&gt;
&lt;p&gt;Check out our &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard guide&lt;/a&gt; to learn how to build your first dashboard.&lt;/p&gt;
&lt;h3 id=&quot;beyond-allen-bradley&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/#beyond-allen-bradley&quot;&gt;Beyond Allen-Bradley&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse isn&#39;t limited to EtherNet/IP. 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&#39;t single-vendor anyway.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; to see how FlowFuse connects your entire operation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/custom-onnx-model/</id>
        <title>Deploy Custom-Trained AI Models: Using ONNX with Node-RED and FlowFuse</title>
        <summary>Using ONNX runtime to run inference in Node-RED</summary>
        <updated>2025-10-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/custom-onnx-model/"/>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;FlowFuse is introducing a new set of AI nodes to make it easier than ever to integrate AI and machine learning into your Node-RED workflows.
In this guide, you will learn how to train an image classifier model, and use it with the new FlowFuse AI Nodes to recognise your own products, components - or anything else you can imagine.&lt;/p&gt;
&lt;h3 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this article, we will be building a PyTorch-based image classification model to identify fruit types (apple, kiwi, mango) using a dataset of labelled images.
Of course, you would typically be classifying your own things like your company widgets and products, but for the sake of learning the process, we will be using images of fruit.
Once the model is trained, it is exported to the ONNX format, it is then ready for use with the new FlowFuse AI nodes.&lt;/p&gt;
&lt;p&gt;Note: The code and sample dataset used in this tutorial can be downloaded from &lt;a href=&quot;https://website-data.s3.eu-west-1.amazonaws.com/2025-10-onnx-model-training-dataset.zip&quot;&gt;this link&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;some-background-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#some-background-first&quot;&gt;Some background first&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The process we will use is commonly referred to as &amp;quot;transfer learning&amp;quot;. This is where you take a pre-trained model and fine-tune it on your own dataset.
This is a common approach in deep learning as it allows us to leverage the knowledge learned by the pre-trained model and adapt it to our specific task with a smaller dataset.  For reference, this tutorial will use ResNet-18 which is an 18-layer Residual Network (ResNet), a convolutional neural network (CNN) architecture that uses &amp;quot;skip connections&amp;quot; to help train very deep networks by addressing the vanishing gradient problem. Pre-trained ResNet-18 models are often trained on the ImageNet dataset and are widely used for image classification of 1000 categories.&lt;/p&gt;
&lt;h3 id=&quot;overview-of-operations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#overview-of-operations&quot;&gt;Overview of operations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The 3 main steps to achieve this involves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Setting up a Python environment with PyTorch, TorchVision, ONNX, and ONNX Runtime.&lt;/li&gt;
&lt;li&gt;Organizing your dataset into train, validation, and test folders for each class.&lt;/li&gt;
&lt;li&gt;Perform &amp;quot;transfer learning&amp;quot; to fine-tune the model against your images &amp;amp; generate the ONNX model.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&#39;s get started...&lt;/p&gt;
&lt;h3 id=&quot;setup-the-environment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#setup-the-environment&quot;&gt;Setup the environment&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;pre-requisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#pre-requisites&quot;&gt;Pre-requisites&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This tutorial was tested on Ubuntu using Python 3 and &lt;code&gt;pyenv&lt;/code&gt; for environment management.&lt;/p&gt;
&lt;p&gt;For the sake of brevity, from this point forward, the tutorial will assume you are using a debian based operating system and &lt;code&gt;pyenv&lt;/code&gt;.
Instructions will need to be adapted if you are using something else.&lt;/p&gt;
&lt;h5 id=&quot;python-tools&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#python-tools&quot;&gt;Python tools&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;Ensure you have &lt;code&gt;pyenv&lt;/code&gt; and &lt;code&gt;pyenv-virtualenv&lt;/code&gt; installed.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-62&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-62&quot; class=&quot;language-bash&quot;&gt;pyenv &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;br /&gt;pyenv virtualenv &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-62&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you don&#39;t have them installed, this &lt;a href=&quot;https://medium.com/@aashari/easy-to-follow-guide-of-how-to-install-pyenv-on-ubuntu-a3730af8d7f0&quot;&gt;Medium article&lt;/a&gt; worked well in our case.&lt;/p&gt;
&lt;h5 id=&quot;sub-dependencies&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#sub-dependencies&quot;&gt;Sub dependencies&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;During setup and testing, my installation failed at the last step due to missing &lt;code&gt;bz2&lt;/code&gt; support (a TorchVision dependency).
If you encounter this, you would need to install &lt;code&gt;libbz2&lt;/code&gt; then you would need to rebuild your python environment.
To save time, I recommend that you perform the steps below now to ensure the dependencies are installed and avoid the mis-step.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-72&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-72&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; update&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; libbz2-dev liblzma-dev libsqlite3-dev libssl-dev zlib1g-dev libffi-dev build-essential&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-72&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;virtual-environment-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#virtual-environment-setup&quot;&gt;Virtual Environment Setup&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Install python 3.10.14 (or any version compatible with pytorch and onnx):&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-79&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-79&quot; class=&quot;language-bash&quot;&gt;pyenv &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.10&lt;/span&gt;.14&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-79&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Create a new virtual environment:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-83&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-83&quot; class=&quot;language-bash&quot;&gt;pyenv virtualenv &lt;span class=&quot;token number&quot;&gt;3.10&lt;/span&gt;.14 venv_py3_10_14_pytorch&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-83&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Activate the virtual environment:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-87&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-87&quot; class=&quot;language-bash&quot;&gt;pyenv activate venv_py3_10_14_pytorch&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-87&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;NOTE: Depending on your shell, your commandline may become decorated with the name of the virtual environment.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Install the required packages:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-94&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-94&quot; class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--upgrade&lt;/span&gt; pip&lt;br /&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; torch torchvision onnx onnxruntime matplotlib numpy&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-94&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Create a working directory&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-98&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-98&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; ~/my-py-projects&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/my-py-projects&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; pytorch-onnx&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; pytorch-onnx&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Associate this directory with the virtual env we created earlier&lt;/span&gt;&lt;br /&gt;pyenv &lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; venv_py3_10_14_pytorch&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-98&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;(Optional) Create a &lt;code&gt;requirements.txt&lt;/code&gt; file to document the packages used in this project:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-102&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-102&quot; class=&quot;language-bash&quot;&gt;pip freeze &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; requirements.txt&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-102&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;organizing-your-dataset&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#organizing-your-dataset&quot;&gt;Organizing your dataset&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For this example, I have created a simple dataset of images of apples, kiwis, and mangos.
You can use your own dataset or download a dataset from the internet (e.g. &lt;a href=&quot;https://www.kaggle.com/datasets/&quot;&gt;this one&lt;/a&gt; or &lt;a href=&quot;https://images.cv/search-labeled-image-dataset&quot;&gt;this one&lt;/a&gt;).
Just make sure to organize the images in the following structure:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-109&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-109&quot; class=&quot;language-bash&quot;&gt;data/&lt;br /&gt;    train/&lt;br /&gt;        apples/&lt;br /&gt;            apple1.jpg&lt;br /&gt;            apple2.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        kiwis/&lt;br /&gt;            kiwi1.jpg&lt;br /&gt;            kiwi2.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        mangos/&lt;br /&gt;            mango1.jpg&lt;br /&gt;            mango2.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;    val/&lt;br /&gt;        apples/&lt;br /&gt;            apple3.jpg&lt;br /&gt;            apple4.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        kiwis/&lt;br /&gt;            kiwi3.jpg&lt;br /&gt;            kiwi4.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        mangos/&lt;br /&gt;            mango3.jpg&lt;br /&gt;            mango4.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;    test/&lt;br /&gt;        apples/&lt;br /&gt;            apple5.jpg&lt;br /&gt;            apple6.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        kiwis/&lt;br /&gt;            kiwi5.jpg&lt;br /&gt;            kiwi6.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;        mangos/&lt;br /&gt;            mango5.jpg&lt;br /&gt;            mango6.jpg&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-109&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Now, inside &lt;code&gt;~/my-py-projects/pytorch-onnx/&lt;/code&gt; you should have:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-113&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-113&quot; class=&quot;language-bash&quot;&gt;pytorch-onnx/&lt;br /&gt;│&lt;br /&gt;├── data/&lt;br /&gt;│   ├── train/&lt;br /&gt;│   │   ├── apples/&lt;br /&gt;│   │   ├── kiwis/&lt;br /&gt;│   │   └── mangos/&lt;br /&gt;│   ├── val/&lt;br /&gt;│   └── test/&lt;br /&gt;│&lt;br /&gt;├── fruit_classifier.py   &lt;span class=&quot;token comment&quot;&gt;# we will create this shortly&lt;/span&gt;&lt;br /&gt;└── requirements.txt      &lt;span class=&quot;token comment&quot;&gt;# optional&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-113&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;fine-tune-the-model&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#fine-tune-the-model&quot;&gt;Fine-tune the model&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we can create a simple pytorch model to classify the images.&lt;/p&gt;
&lt;p&gt;Create a new file called &lt;code&gt;fruit_classifier.py&lt;/code&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-123&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-123&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Use nano to create the file (you can use your favorite editor e.g. vim, code, etc)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; fruit_classifier.py&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-123&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Add the following code:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-127&quot;&gt;
  &lt;pre class=&quot;language-python&quot;&gt;&lt;code id=&quot;code-127&quot; class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fruit_classifier.py&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torch&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nn &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; nn&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;optim &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; optim&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; DataLoader&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torchvision&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transforms &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; transforms&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torchvision&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datasets &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; datasets&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; torchvision&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;models &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; models&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; onnxruntime &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ort&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; numpy &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; np&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Dataset ---&lt;/span&gt;&lt;br /&gt;data_dir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;br /&gt;transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transforms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Compose&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    transforms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Resize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    transforms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ToTensor&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    transforms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Normalize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mean&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.485&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.456&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.406&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                         std&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.229&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.224&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.225&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;train_dataset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datasets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ImageFolder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data_dir&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/train&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transform&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;val_dataset   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datasets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ImageFolder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data_dir&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/val&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transform&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;test_dataset  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datasets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ImageFolder&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;data_dir&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/test&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transform&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;train_loader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DataLoader&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;train_dataset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; batch_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shuffle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;val_loader   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DataLoader&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val_dataset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; batch_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shuffle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;test_loader  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DataLoader&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;test_dataset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; batch_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shuffle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Class mapping:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; train_dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;class_to_idx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;device &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cuda&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cuda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;is_available&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cpu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Model ---&lt;/span&gt;&lt;br /&gt;model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; models&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resnet18&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;weights&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;models&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ResNet18_Weights&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IMAGENET1K_V1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Linear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;in_features&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;train_dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;criterion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CrossEntropyLoss&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;optimizer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; optim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Adam&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parameters&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lr&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1e-4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Training ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_epochs&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; epoch &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_epochs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;train&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        running_loss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; inputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; train_loader&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            inputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            optimizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zero_grad&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            outputs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            loss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; criterion&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;outputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            loss&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backward&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            optimizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            running_loss &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; loss&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        avg_loss &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; running_loss &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;train_loader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Epoch &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;epoch&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, Loss: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;avg_loss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.4f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Evaluation ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    correct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; total &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;no_grad&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; inputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; loader&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;            inputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            outputs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            _&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;outputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            correct &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;preds &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            total &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; correct &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; total&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Export to ONNX ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;export_model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    dummy_input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;randn&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; device&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;device&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    torch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onnx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;export&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;               &lt;span class=&quot;token comment&quot;&gt;# model being run&lt;/span&gt;&lt;br /&gt;        dummy_input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;# model input (or a tuple for multiple inputs)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;fruit_classifier.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# where to save the model (can be a file or file-like object)&lt;/span&gt;&lt;br /&gt;        export_params&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# store the trained parameter weights inside the model file&lt;/span&gt;&lt;br /&gt;        opset_version&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# the ONNX version to export the model to&lt;/span&gt;&lt;br /&gt;        do_constant_folding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# whether to execute constant folding for optimization&lt;/span&gt;&lt;br /&gt;        input_names&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;input&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# the model&#39;s input names&lt;/span&gt;&lt;br /&gt;        output_names&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;output&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# the model&#39;s output names&lt;/span&gt;&lt;br /&gt;        dynamic_axes&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;batch_size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;output&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;batch_size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Model exported to fruit_classifier.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Test with ONNX Runtime ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test_onnx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    ort_session &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ort&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;InferenceSession&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fruit_classifier.onnx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;to_numpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tensor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;detach&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cpu&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; tensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requires_grad &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; tensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cpu&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    inputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;test_loader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    ort_inputs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; to_numpy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    ort_outs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ort_session&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ort_inputs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    pred_class &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;argmax&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ort_outs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ONNX Prediction:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; train_dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pred_class&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# --- Main ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; __name__ &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    train&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_epochs&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    val_acc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; evaluate&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val_loader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Validation Accuracy: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;val_acc&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.2%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    export_model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    test_onnx&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-127&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;run-the-fruit_classifier.py-python-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#run-the-fruit_classifier.py-python-script&quot;&gt;Run the fruit_classifier.py Python script&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now you can run the script that will train the model, export it to ONNX format, and run a quick classification test using the ONNX Runtime:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-134&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-134&quot; class=&quot;language-bash&quot;&gt;python fruit_classifier.py&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-134&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;What you should see:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-138&quot;&gt;
  &lt;pre class=&quot;language-log&quot;&gt;&lt;code id=&quot;code-138&quot; class=&quot;language-log&quot;&gt;&lt;span class=&quot;token property&quot;&gt;Class mapping:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;apple&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;kiwi&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mango&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;}&lt;/span&gt;&lt;br /&gt;Epoch &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loss&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.7811&lt;/span&gt;&lt;br /&gt;Epoch &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loss&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1383&lt;/span&gt;&lt;br /&gt;Epoch &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loss&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0671&lt;/span&gt;&lt;br /&gt;Epoch &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loss&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0399&lt;/span&gt;&lt;br /&gt;Epoch &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loss&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0184&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;Validation Accuracy:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80.95&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;br /&gt;Model exported to fruit_classifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onnx&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;ONNX Prediction:&lt;/span&gt; apple&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-138&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you changed the data set from fruit to your use own images and classifications, it will output a different &lt;code&gt;Class mapping&lt;/code&gt; that you will need to use in the Node-RED flow on the next step - make a note of this.&lt;/p&gt;
&lt;h3 id=&quot;using-your-newly-generated-onnx-model-with-the-flowfuse-onnx-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#using-your-newly-generated-onnx-model-with-the-flowfuse-onnx-node&quot;&gt;Using your newly generated ONNX Model with the FlowFuse ONNX Node&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Import the finished ONNX model into a location in the file system where your Node-RED instance can access it
&lt;ul&gt;
&lt;li&gt;In FlowFuse cloud you can do this via the Assets tab&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Import the demo flow
&lt;ul&gt;
&lt;li&gt;Open your Node-RED editor&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;CTRL-I&lt;/code&gt; or select &lt;code&gt;Import&lt;/code&gt; from the menu to open the Import Dialog&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Examples&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;@FlowFuse/nr-ai-nodes&lt;/strong&gt; entry&lt;/li&gt;
&lt;li&gt;Click the demo named &lt;strong&gt;advanced-custom-model&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Import&lt;/strong&gt; Button&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Double click the ONNX node to open the configuration dialog&lt;/li&gt;
&lt;li&gt;Enter the path to your ONNX model in the &lt;strong&gt;Path&lt;/strong&gt; field&lt;/li&gt;
&lt;li&gt;If necessary, update the classifications (labels) in the Function node named &lt;strong&gt;load labels&lt;/strong&gt; as noted in the previous section&lt;/li&gt;
&lt;li&gt;Deploy the flow&lt;/li&gt;
&lt;li&gt;Click the inject button on the left of the flow to trigger an inference&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing how to import demo flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/custom-onnx-mode--import-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing how to import demo flow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing inference in action&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/custom-onnx-mode--in-action.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing inference in action&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;supplementary-notes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#supplementary-notes&quot;&gt;Supplementary Notes&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;clean-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/custom-onnx-model/#clean-up&quot;&gt;Clean up&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To deactivate the virtual environment when you&#39;re done, simply run:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-236&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-236&quot; class=&quot;language-bash&quot;&gt;pyenv deactivate&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-236&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can remove the &lt;code&gt;__pycache__&lt;/code&gt; and other temporary files if they were created:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-240&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-240&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; __pycache__&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; runs/ logs/ checkpoints/&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-240&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you want to completely remove the virtual environment, you can do so with:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-244&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-244&quot; class=&quot;language-bash&quot;&gt;pyenv uninstall venv_py3_10_14_pytorch&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-244&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/</id>
        <title>Beyond Cloud AI Orchestration: Why the Future is Hybrid Edge-Cloud Intelligence</title>
        <summary>While cloud orchestration excels in digital workflows, the industrial world needs a hybrid approach.</summary>
        <updated>2025-10-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/"/>
        <author><name>Pablo Filomeno</name></author>
        <content type="html">&lt;p&gt;Congratulations to n8n on their &lt;a href=&quot;https://blog.n8n.io/series-c/&quot;&gt;Series C funding round&lt;/a&gt;! This is a fantastic milestone and a clear signal that the market has moved beyond AI experimentation and into the serious business of production deployment. Platforms like n8n are mastering what we call centralized orchestration: creating cloud-native &amp;quot;brains&amp;quot; that connect digital services, APIs, and data sources to execute complex workflows. This approach excels for digital-first applications and represents a crucial evolution in workflow automation.&lt;/p&gt;
&lt;p&gt;But for industrial applications, we need to think beyond traditional cloud orchestration.&lt;/p&gt;
&lt;p&gt;The tech world is buzzing with talk of AI agents and orchestration platforms, and the energy around n8n&#39;s recent funding is proof of this momentum. This energy is a fantastic sign of a maturing market, proving that we&#39;ve moved beyond AI experimentation and into the serious business of production deployment.&lt;/p&gt;
&lt;p&gt;Cloud orchestration platforms excel at what they&#39;re designed for: connecting digital services, managing API workflows, and orchestrating cloud-native applications. However, for the industries that power our physical world—manufacturing, logistics, energy, and infrastructure—we need complementary approaches that address the unique requirements of operational technology. This is where hybrid edge-cloud architectures become essential.&lt;/p&gt;
&lt;h2 id=&quot;industrial-requirements%3A-where-cloud-only-solutions-face-challenges&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/#industrial-requirements%3A-where-cloud-only-solutions-face-challenges&quot;&gt;Industrial Requirements: Where Cloud-Only Solutions Face Challenges&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When operations involve real-world assets like factory machinery, remote sensors, or logistics fleets, purely centralized approaches encounter specific industrial constraints. For applications where milliseconds matter—such as emergency shutdowns or quality control decisions—the latency of cloud round-trips can be too slow for critical responses. Connectivity challenges in industrial environments, from remote oil platforms to underground mining operations, require systems that can operate intelligently even when cloud connections are intermittent.&lt;/p&gt;
&lt;p&gt;Additionally, the economics of data movement become significant at industrial scale. Streaming continuous data from thousands of sensors to the cloud for processing can be costly and inefficient, especially when much of that processing could happen locally. Many industries also have regulatory requirements that mandate certain operational data remain on-premise for compliance and security reasons.&lt;/p&gt;
&lt;p&gt;These constraints don&#39;t invalidate cloud orchestration—they highlight the need for hybrid approaches that leverage both cloud capabilities and edge intelligence where each excels.&lt;/p&gt;
&lt;h2 id=&quot;the-next-paradigm%3A-hybrid-edge-cloud-intelligence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/#the-next-paradigm%3A-hybrid-edge-cloud-intelligence&quot;&gt;The Next Paradigm: Hybrid Edge-Cloud Intelligence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The future of industrial AI isn&#39;t choosing between cloud or edge—it&#39;s intelligently combining both. Rather than replacing cloud orchestration, the industrial world needs a hybrid architecture: a distributed nervous system where cloud orchestration handles high-level coordination and data aggregation, while edge intelligence manages real-time operations and local decision-making.&lt;/p&gt;
&lt;p&gt;In this paradigm, AI operates at multiple levels. Edge devices handle immediate responses—predictive maintenance alerts, quality control decisions, and safety shutdowns—without waiting for cloud communication. Meanwhile, cloud orchestration excels at what it does best: aggregating data from multiple sites, running complex analytics, coordinating across systems, and managing enterprise-wide workflows. This creates a complementary relationship where each layer operates within its strengths.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-bridging-edge-and-cloud-intelligence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/#flowfuse%3A-bridging-edge-and-cloud-intelligence&quot;&gt;FlowFuse: Bridging Edge and Cloud Intelligence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the market builds excellent tools for cloud-based AI orchestration, FlowFuse specializes in the hybrid approach that industrial applications demand. Built on the proven foundation of Node-RED, our platform provides engineers with a unified control tower to manage both cloud orchestration and edge intelligence at scale.&lt;/p&gt;
&lt;p&gt;FlowFuse Cloud enables centralized management and coordination, while our edge capabilities allow thousands of Node-RED instances to operate intelligently at remote locations. This hybrid architecture lets you seamlessly integrate the physical and digital worlds—leveraging cloud orchestration for enterprise workflows while maintaining real-time edge intelligence where it matters most.&lt;/p&gt;
&lt;p&gt;Our FlowFuse Expert simplifies the creation and management of complex logic across both cloud and edge environments, democratizing advanced automation without requiring specialized data science skills. Soon, with our upcoming AI Agent nodes, FlowFuse will enable powerful AI agents to operate seamlessly across the entire hybrid architecture, from cloud coordination to edge execution.&lt;/p&gt;
&lt;h2 id=&quot;conclusion%3A-the-power-of-hybrid-intelligence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/#conclusion%3A-the-power-of-hybrid-intelligence&quot;&gt;Conclusion: The Power of Hybrid Intelligence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The rise of AI orchestration platforms represents an important evolution in automation technology. These tools excel in their domain and will continue to play a crucial role in digital transformation initiatives.&lt;/p&gt;
&lt;p&gt;For industrial applications, the future lies in hybrid architectures that combine the strengths of both approaches. Cloud orchestration provides the coordination, analytics, and enterprise integration capabilities that modern businesses require, while edge intelligence delivers the real-time responsiveness and resilience that industrial operations demand.&lt;/p&gt;
&lt;p&gt;Choosing the right approach comes down to understanding your requirements. For digital-first applications, cloud orchestration platforms offer powerful solutions. For industrial and IoT applications that bridge physical and digital worlds, hybrid edge-cloud architectures provide the comprehensive intelligence needed to succeed.&lt;/p&gt;
&lt;h2 id=&quot;ready-to-build-the-future-of-industrial-ai%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/the-ai-orchestration-hype/#ready-to-build-the-future-of-industrial-ai%3F&quot;&gt;Ready to Build the Future of Industrial AI?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is built for the challenges of industrial and IoT data. Whether you&#39;re implementing Industry 4.0 initiatives or building predictive maintenance systems, we provide the platform to deploy and manage intelligence across both cloud and edge environments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start building today: Try FlowFuse free&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/node-red-revolution/</id>
        <title>The Node-RED Revolution: How Low-Code is Democratizing Industrial Automation</title>
        <summary>Looking back on where Node-RED came from to understand the impact it has had on industry</summary>
        <updated>2025-10-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/node-red-revolution/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;To understand the impact Node-RED has had on industrial automation, it&#39;s useful to understand where it has come from and what has enabled its success.&lt;/p&gt;
&lt;p&gt;Almost 20 years ago, I was helping to develop an MQTT broker. One of the features of the broker was to create message transformations; taking messages from one topic, modifying their structure and republishing on another topic. It was a really useful feature, but it was only ever exposed via a programming API. Customers had to write lots of code to make use of it. It was also difficult to examine what transformations had already been created. I would often find myself getting a piece of paper and writing out the transformations to help spot any unexpected interactions between them. At the time, I dreamed of a way to better visualise what was happening - but that was far out of scope of our requirements at the time.&lt;/p&gt;
&lt;p&gt;Fast forward a few years, and I found myself faced with a similar challenge; working on customer projects that often required pulling data from different sources and having to write the same bits of code again and again to get the job done. This time, I was more in a position to do something about it, and after a couple days of coding, I had a simple demo of a tool that could visualise MQTT topics and how messages would get routed between them. Then we added a way to pull data from a Serial port, a way to run custom code against the messages, a way to do HTTP requests - each week, a new customer project would raise a new requirement and this little side project would prove its worth again and again.&lt;/p&gt;
&lt;p&gt;This is, of course, the Node-RED origin story. But how has this little side project become the widely adopted success it has - and why is it so valuable to Industrial users? I think there are three parts to this; its low-code visual nature, its Open Source availability and its extensibility.&lt;/p&gt;
&lt;h2 id=&quot;low-code-visualisation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-revolution/#low-code-visualisation&quot;&gt;Low-Code Visualisation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of my original motivations for Node-RED was to save time by not having to write the same pieces of boiler-plate code each time I needed to do a particular task. Dragging a node into the workspace takes seconds and replaces minutes - or even hours - of traditional code development time.&lt;/p&gt;
&lt;p&gt;This abstraction empowers anyone to start building applications in Node-RED. System engineers understand the problem they are trying to solve. Node-RED gives them the ability to build their solutions without having to think about the lines of code each node represents - they can focus on the task at hand.&lt;/p&gt;
&lt;h2 id=&quot;open-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-revolution/#open-source&quot;&gt;Open Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The move away from proprietary solutions gives users more control and influence over the tools they use. Open Source Software brings principles of collaboration, transparency, and interoperability. It was a very deliberate choice to make Node-RED Open Source in its early days; we knew the project’s future lay in building an open community around it - with contributors from many backgrounds.&lt;/p&gt;
&lt;h2 id=&quot;extensibility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-revolution/#extensibility&quot;&gt;Extensibility&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A natural consequence of the Open Source path the project took was to make it easy to extend what Node-RED could do. Enabling the community to build their own nodes greatly accelerated the adoption of the project - with the Open Source ethos underpinning that work.&lt;/p&gt;
&lt;p&gt;Whilst we see Node-RED used in many industries, it finds a natural home in the Industrial automation space. Being able to run anywhere from edge-of-network devices to the cloud gives a lot of flexibility in the types of solutions it can be applied to. At its heart, Node-RED is all about accessing data, wherever it may be and doing something meaningful with that data.&lt;/p&gt;
&lt;p&gt;We see it being used alongside traditional PLCs, providing an easier point of integration - pulling data from many different systems in one place, providing a dashboard visualization in situ, and making the data available to the wider organization. Having a consistent developer experience for all those tasks makes Node-RED a natural choice.&lt;/p&gt;
&lt;h2 id=&quot;scaling-node-red-within-your-organization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-revolution/#scaling-node-red-within-your-organization&quot;&gt;Scaling Node-RED within your organization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Through the early life of the project, we focussed on the core of Node-RED being a high-quality, reliable, low-code development tool. Through the community, we knew there were companies beginning to adopt Node-RED at scale, but some of the challenges they were facing were out of scope of what the core project could address.&lt;/p&gt;
&lt;p&gt;The flexibility of Node-RED comes at a cost of how you scale and manage your Node-RED infrastructure. All organizations have a responsibility to keep their IT infrastructure secured and well-maintained - and that has to be considered when adopting any technology.&lt;/p&gt;
&lt;p&gt;For all of its strengths, the choice of Open Source at the core does pose some questions that should not be overlooked. For example, who can be relied on to fix issues if you don’t have the engineering capacity within your own organization? How do you manage all of those Node-RED instances throughout your organization?&lt;/p&gt;
&lt;p&gt;These were the questions that motivated me to start FlowFuse - and is where we elevate Node-RED to be a robust enterprise-ready platform. Just as the early development of Node-RED was driven by our own requirements, FlowFuse has been built based on first-hand experience of what’s needed to scale Node-RED.&lt;/p&gt;
&lt;p&gt;A great example is one of our early customers who is a large manufacturer in the US. They began adopting Node-RED in 2018 across their facilities. At the time, they had to build a lot of custom automation to manage it, but the overheads were becoming unmanageable. With their small IT team, they found it hard to properly track the different versions of flows deployed across their sites. They moved over to FlowFuse which has enabled them to continue scaling their operations and now have thousands of Node-RED instances being managed by the platform.&lt;/p&gt;
&lt;p&gt;This is a common pattern we see; FlowFuse solves the operational challenges that slow down digital transformation; engineers are able to focus on solving real business problems with confidence.&lt;/p&gt;
&lt;h2 id=&quot;join-us-at-node-red-con&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-revolution/#join-us-at-node-red-con&quot;&gt;Join us at Node-RED Con&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next month we’re sponsoring the Node-RED Con virtual event - a free day of talks from the Node-RED community all about how it’s being used in industry. There are lots of fascinating talks scheduled and I’d urge you to &lt;a href=&quot;https://events.zoom.us/ev/AqhqiQ8mTK2lnAoOEH8c8TA1a_9MzVhZq_T7d1-kMHlHDt2_Qh_0~AtAGpC_uhX5LxGrRFYeO63TLtQlUXVUdpy3DY5mEZFgC79PyUeKZzgp8njVUDVZdS3SBo8HS1wGVPdosNhe2VVxCpw&quot;&gt;register to attend&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/</id>
        <title>What&#39;s the Difference Between Node-RED and FlowFuse</title>
        <summary>Understanding how FlowFuse extends Node-RED from a powerful development tool to a scalable enterprise platform</summary>
        <updated>2025-10-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse is an industrial data platform built on Node-RED. Many Fortune 500 manufacturers and Industrial IoT companies use it to run mission-critical operations where downtime is not an option.&lt;/p&gt;
&lt;p&gt;If you&#39;re hearing about FlowFuse for the first time, you might wonder: &lt;em&gt;&amp;quot;If it&#39;s built on Node-RED, what makes it different?&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This article answers that question. You&#39;ll learn what FlowFuse adds to Node-RED, whether it competes with Node-RED, and how to decide which platform is right for you.&lt;/p&gt;
&lt;h2 id=&quot;where-node-red-came-from&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#where-node-red-came-from&quot;&gt;Where Node-RED Came From&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To understand what FlowFuse adds, it helps to first look at Node-RED itself.&lt;/p&gt;
&lt;p&gt;In 2013, Nick O&#39;Leary (CTO and Founder of FlowFuse) and Dave Conway-Jones at IBM identified a problem: connecting devices, APIs, and services required hundreds of lines of code for tasks that should be straightforward. Their solution was to make programming visual. Drag nodes, draw connections, deploy your logic.&lt;/p&gt;
&lt;p&gt;Engineers who understood systems but couldn&#39;t code could suddenly build applications. Tasks that took weeks were completed in hours. Node-RED runs on laptops, Raspberry Pis, factory floor gateways, and enterprise servers. The community has built thousands of nodes for most scenarios you&#39;ll encounter.&lt;/p&gt;
&lt;p&gt;For small projects, prototypes, and learning, Node-RED provides what you need without overhead.&lt;/p&gt;
&lt;h2 id=&quot;when-limitations-surface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#when-limitations-surface&quot;&gt;When Limitations Surface&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your Node-RED flow works. It monitors equipment, processes data, and displays dashboards. Then the question arises: &lt;em&gt;&#39;Can we deploy this across all 50 of our factories efficiently, without wasting time or money?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That question exposes the limitations of standalone Node-RED:&lt;/p&gt;
&lt;p&gt;You need to deploy to 50 sites across three continents without manual setup at each location. Five engineers need to work on improvements without conflicts. You need alerts when any instance goes down because downtime stops production and costs money. Your security team requires SSO integration, role-based access control, and audit trails. You need to push updates to all sites at once, not travel to each location over weeks. When someone deploys a breaking change on Friday afternoon, you need to roll it back in seconds.&lt;/p&gt;
&lt;p&gt;This is where Node-RED ends and FlowFuse begins.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node-RED gives you the tools to build. FlowFuse provides the infrastructure to deploy, manage, and scale what you&#39;ve built.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-flowfuse-adds&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#what-flowfuse-adds&quot;&gt;What FlowFuse Adds&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse doesn&#39;t replace Node-RED. You use the same visual editor, nodes, and flows. FlowFuse adds the operational layer that transforms Node-RED from a development tool into a production platform.&lt;/p&gt;
&lt;h3 id=&quot;security-and-compliance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#security-and-compliance&quot;&gt;Security and Compliance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Standard Node-RED leaves authentication to you—typically basic auth or custom middleware. For personal projects, this suffices. Production environments controlling industrial systems need more.&lt;/p&gt;
&lt;p&gt;FlowFuse provides role-based access control (RBAC) to define who edits flows versus who views them. Single Sign-On via SAML, LDAP, and OIDC integrates with your existing identity systems. Audit logs capture every deployment with details on who made changes and when. Database credentials and API tokens are managed through encrypted secrets storage, keeping them out of flow exports and version control.&lt;/p&gt;
&lt;p&gt;For supply chain security, FlowFuse generates a Software Bill of Materials (SBOM) listing every node and dependency across your instances. Security teams can scan for vulnerabilities and track what needs updating.&lt;/p&gt;
&lt;h3 id=&quot;team-collaboration-and-version-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#team-collaboration-and-version-control&quot;&gt;Team Collaboration and Version Control&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED was built for individual developers. When two people edit the same instance, the last save wins. No version history exists. No way to review changes before deployment. No rollback option.&lt;/p&gt;
&lt;p&gt;FlowFuse enables multi-user teams working on shared projects with proper permissions. Every deployment creates a snapshot—a complete record of your flows at that point in time. Compare snapshots to track changes or restore previous versions when deployments break production.&lt;/p&gt;
&lt;h3 id=&quot;remote-device-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#remote-device-management&quot;&gt;Remote Device Management&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED instances running on edge devices in remote factories, warehouses, or hard-to-reach locations create operational challenges. Troubleshooting means traveling on-site or configuring complex VPN access.&lt;/p&gt;
&lt;p&gt;FlowFuse provides centralized management through its Device Agent—a lightweight service installed on remote devices that establishes secure connections back to your FlowFuse instance. From one dashboard, you see and control your entire fleet. Open any device&#39;s editor or view its logs through secure tunnels without exposing ports or setting up VPNs. Push updates over-the-air to individual devices or groups.&lt;/p&gt;
&lt;h3 id=&quot;deployment-pipelines-and-scalability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#deployment-pipelines-and-scalability&quot;&gt;Deployment Pipelines and Scalability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Standalone Node-RED moves code from development to production through manual export and import. This doesn&#39;t scale and introduces errors with each manual step. Managing one instance is simple. Managing hundreds requires standardization.&lt;/p&gt;
&lt;p&gt;FlowFuse builds structured deployment into the platform. Create Development, Staging, and Production environments for each project. Promote snapshots between stages with single clicks. Organize devices into groups by location or function, then target updates to specific groups. Deploy to all North American packaging lines while leaving European facilities on their current version. The platform organizes work through teams and projects, giving each group isolated resources while maintaining central oversight.&lt;/p&gt;
&lt;h3 id=&quot;observability-and-monitoring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#observability-and-monitoring&quot;&gt;Observability and Monitoring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Standalone Node-RED displays logs from a single instance. When you&#39;re running multiple instances across different locations, you need centralized visibility. Building this yourself means integrating Prometheus, configuring exporters, creating Grafana dashboards, and setting up alerting—weeks of specialized work.&lt;/p&gt;
&lt;p&gt;FlowFuse provides centralized observability. View logs from any instance, check audit logs for specific deployments, monitor real-time status showing when each instance was last seen, and track CPU and memory usage across your entire fleet—all from one interface.&lt;/p&gt;
&lt;h3 id=&quot;managed-infrastructure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#managed-infrastructure&quot;&gt;Managed Infrastructure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Running Node-RED means managing servers or edge devices, handling installations, planning updates, configuring backups, and preparing disaster recovery. At scale, this becomes a full-time responsibility.&lt;/p&gt;
&lt;p&gt;FlowFuse Cloud is fully managed—they handle infrastructure, you build applications. FlowFuse Self-Hosted runs on your infrastructure but manages orchestration, updates, and monitoring. Both options deliver over-the-air updates for Node-RED versions, security patches, and configuration changes without downtime.&lt;/p&gt;
&lt;h3 id=&quot;certified-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#certified-nodes&quot;&gt;Certified Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Node-RED community has built thousands of nodes covering most use cases. Production environments need assurance about maintenance, security vulnerabilities, and long-term support.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s Certified Nodes program vets community contributions for quality, security, and maintenance. FlowFuse takes ongoing responsibility for certified nodes and accepts certification requests for nodes you need.&lt;/p&gt;
&lt;h3 id=&quot;development-acceleration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#development-acceleration&quot;&gt;Development Acceleration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED&#39;s visual programming is fast, but real-world development has friction points. Complex function nodes and UI templates require time and coding skill. Understanding teammates&#39; flows isn&#39;t always straightforward. Building the same patterns across projects becomes repetitive.&lt;/p&gt;
&lt;p&gt;FlowFuse Expert tackles these challenges directly in the editor. Describe your need in plain language—it generates function nodes or UI templates, explains existing flows, writes SQL queries, suggests relevant nodes, and creates documentation. This speeds up experienced developers while making Node-RED accessible to those still learning.&lt;/p&gt;
&lt;p&gt;The Blueprint Library provides tested and proven templates for common industrial scenarios—OEE dashboards, Andon systems, operator terminals. Instead of building from scratch, start with working solutions and customize them for your needs.&lt;/p&gt;
&lt;p&gt;Team Library enables reusability within your organization. Export a flow to your Team Library once, and it&#39;s available across all team instances. Your team maintains consistent patterns without recreating the same work.&lt;/p&gt;
&lt;h3 id=&quot;commercial-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#commercial-support&quot;&gt;Commercial Support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED&#39;s community provides excellent support for learning and troubleshooting through forums and discussions. Production outages costing money per minute require faster resolution and guaranteed response times.&lt;/p&gt;
&lt;p&gt;FlowFuse offers commercial support with Service Level Agreements. Work directly with engineers who understand Node-RED internals, have encountered your problems before, and can architect solutions that scale.&lt;/p&gt;
&lt;h2 id=&quot;are-node-red-and-flowfuse-competitors%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#are-node-red-and-flowfuse-competitors%3F&quot;&gt;Are Node-RED and FlowFuse Competitors?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No. Node-RED and FlowFuse are not competitors—they’re complementary. FlowFuse is built directly on top of Node-RED, and the two projects share deep roots. In fact, FlowFuse employees, including Node-RED’s co-creator Nick O’Leary, are among the most active contributors to Node-RED itself. They review pull requests, write code, run Node-RED Con, and maintain long-term support for the community.&lt;/p&gt;
&lt;p&gt;When Node-RED improves, FlowFuse improves too. This is the same dynamic seen in other open-source ecosystems: Linux thrives alongside Red Hat, Kubernetes powers enterprise platforms, and PostgreSQL continues to evolve while vendors provide enterprise features. The open-source project remains free and independent, while the commercial platform adds operational value on top.&lt;/p&gt;
&lt;p&gt;FlowFuse also invests back into the ecosystem. A good example is the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (often called Node-RED Dashboard 2.0), which replaced the deprecated original Node-RED Dashboard. By sponsoring and maintaining this project, FlowFuse ensures the community continues to have a modern, supported visualization tool.&lt;/p&gt;
&lt;p&gt;And importantly, your flows remain portable. Anything you build in FlowFuse works in plain Node-RED. There is no vendor lock-in. FlowFuse exists to extend Node-RED, not replace it.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/node-red-vs-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is a development tool. FlowFuse is a production platform.&lt;/p&gt;
&lt;p&gt;Node-RED lets you build flows. FlowFuse lets you deploy them securely, collaborate, manage them centrally, and scale them across your organization.&lt;/p&gt;
&lt;p&gt;FlowFuse takes what you’ve built in Node-RED and makes it production-ready.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Want to See FlowFuse in Action?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This article highlighted the key differences between Node-RED and FlowFuse, but many advanced features and real-world use cases remain to be explored.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo with our team&lt;/a&gt; to see a complete live demo and discover how FlowFuse extends Node-RED for enterprise operations, or &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;start a free trial&lt;/a&gt; to experience it yourself.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/</id>
        <title>OpenAI&#39;s AgentKit or FlowFuse: Choosing the Right Low-Code App for Your Needs</title>
        <summary>Understanding the key differences between AI-native agent development and edge-focused industrial automation</summary>
        <updated>2025-10-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;AI is moving fast, and with it, the tools we use to build intelligent applications.
Two interesting platforms that have emerged are OpenAI&#39;s AgentKit and FlowFuse.
While both offer AI capabilities, they are designed for very different purposes.
Let&#39;s break down the key differences to help you decide which platform is the
right fit for your needs.&lt;/p&gt;
&lt;h2 id=&quot;openai&#39;s-agentkit%3A-for-building-ai-agents&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/#openai&#39;s-agentkit%3A-for-building-ai-agents&quot;&gt;OpenAI&#39;s AgentKit: For building AI agents&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://openai.com/index/introducing-agentkit/&quot;&gt;OpenAI&#39;s AgentKit&lt;/a&gt; is a toolkit for developers who want to build and deploy AI
agents. Key features of AgentKit include the Agent Builder, a low-code visual environment
for designing multi-agent workflows, and a Connector Registry
for managing data and tool connections.
It also provides ChatKit for embedding chat-based agent experiences,
Expanded Evals for measuring agent performance, and reinforcement fine-tuning (RFT)
to customize reasoning models. Essentially, AgentKit is for developers who are
building AI-native applications and need a robust set of tools to create and
manage their agents within the OpenAI ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-the-bridge-between-the-physical-and-digital-worlds&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/#flowfuse%3A-the-bridge-between-the-physical-and-digital-worlds&quot;&gt;FlowFuse: The Bridge Between the Physical and Digital Worlds&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse, on the other hand, is built on the foundation of &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt;,
also a low-code platform. FlowFuse is specifically designed for industrial and
IoT applications, with a strong focus on what&#39;s known as &amp;quot;the edge&amp;quot; – the
physical world where data is generated by assets like sensors, machines, and other
devices.&lt;/p&gt;
&lt;p&gt;This is where the user&#39;s point about edge data extraction comes in. FlowFuse
excels at managing and scaling fleets of Node-RED instances running on edge
devices. This allows engineers to easily and securely collect data from all their
industrial devices and sensors, effectively &amp;quot;fusing the physical with the digital.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;key-differentiators&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/#key-differentiators&quot;&gt;Key Differentiators&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, how do these two platforms really differ? The first key differentiator is
their core focus. AgentKit is for building AI agents that live in the digital
world of applications and services, whereas FlowFuse is for building and managing
end-to-end data applications that interact with the physical world through edge
devices.&lt;/p&gt;
&lt;p&gt;AgentKit, in its current form, does not have a focus on edge data extraction.
Its purpose is to help you build the &amp;quot;brains&amp;quot; of an AI. FlowFuse&#39;s entire reason
for being is to provide the &amp;quot;nervous system&amp;quot; that connects those brains to the
real world. It&#39;s all about managing edge deployments and ensuring a reliable flow
of data from the edge.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert&lt;/a&gt; is a powerful tool that helps engineers, even those
who aren&#39;t expert coders, to build and manage their Node-RED flows. For instance,
you can describe what you need in plain English and the assistant will generate
the necessary code. It can also analyze a complex flow and explain what it does,
making it easier to maintain. Furthermore, the assistant is a huge time-saver as
it can create realistic test data and even help you build custom dashboards to
visualize your data.&lt;/p&gt;
&lt;p&gt;So, while AgentKit is a toolkit for building AI agents, the FlowFuse Expert
is a tool that helps you build the applications that connect to the physical world.
It empowers any engineer to fuse the physical with the digital by making it easier
than ever to create the logic needed to collect, transform, and act on data from
the edge.&lt;/p&gt;
&lt;p&gt;What&#39;s more, FlowFuse already supports creating &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#new-blueprint%3A-agentic-ai-with-retrieval-augmented-generation&quot;&gt;AI and RAG&lt;/a&gt; integrations and will soon be releasing dedicated MCP nodes that greatly simplifies low-code building of AI Agents.
enabling AI to work directly at the edge. This means you can create AI
agents that not only process data from physical devices but also make decisions
right where the data is generated — with a lot less latency due to less Cloud
round-trips. This is especially important for industrial applications where
milliseconds matter.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Choosing between OpenAI&#39;s AgentKit and FlowFuse comes down to what you&#39;re trying
to achieve. If your goal is to build sophisticated, AI-powered agents for your
applications and your focus is on the digital realm, then OpenAI&#39;s AgentKit is
the clear choice. However, if you need to connect to, manage, and extract data
from physical devices in the real world, and you want to empower your engineers
with an FlowFuse Expert that makes this process easier, then FlowFuse is the
platform for you.&lt;/p&gt;
&lt;p&gt;In the end, these are two powerful but very different tools. AgentKit is for the
AI developer, while FlowFuse is for the industrial engineer who wants to bring
the power of AI to the edge. We&#39;re looking forward to how these technologies can
be combined in future!&lt;/p&gt;
&lt;h2 id=&quot;ready-to-connect-your-physical-world%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/10/open-ai-agent-builder-versus-flowfuse/#ready-to-connect-your-physical-world%3F&quot;&gt;Ready to Connect Your Physical World?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While AgentKit is perfect for building AI agents in the digital realm, FlowFuse
is built for the challenges of industrial and IoT data: managing edge
deployments at scale, connecting to diverse industrial protocols, and ensuring
reliable data flow from thousands of physical devices.&lt;/p&gt;
&lt;p&gt;Whether you&#39;re monitoring production lines, building predictive maintenance
systems, or implementing Industry 4.0 initiatives, FlowFuse provides the
infrastructure to collect, transform, and act on data from the edge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start building today:&lt;/strong&gt; &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse free&lt;/a&gt; or  &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt; to
see how we help teams manage industrial data at scale.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/</id>
        <title>Modbus RTU (RS485/RS422/RS232) Communications with FlowFuse</title>
        <summary>Step-by-step guide to using Modbus RTU with FlowFuse for industrial automation.</summary>
        <updated>2025-09-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Modbus RTU is one of the most widely used communication protocols in industrial automation. It allows you to read sensor data, monitor equipment status, and control devices through a simple master-slave architecture. This guide will walk you through everything you need to know to start reading and writing industrial data with FlowFuse (a platform built around Node-RED with enterprise-level capabilities).&lt;/p&gt;
&lt;p&gt;Whether you&#39;re connecting a single sensor or building a comprehensive industrial monitoring system, this step-by-step guide will show you how to leverage FlowFuse&#39;s powerful capabilities to bridge the gap between legacy industrial devices and modern data systems.&lt;/p&gt;
&lt;h2 id=&quot;understanding-modbus-rtu-basics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#understanding-modbus-rtu-basics&quot;&gt;Understanding Modbus RTU Basics&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus RTU operates on a &lt;strong&gt;master–slave system&lt;/strong&gt;. Unlike its TCP counterpart, it runs over serial connections (RS485/RS422/RS232), making it extremely reliable in environments where network connectivity may be unstable. The protocol has been battle-tested in harsh conditions for decades, which is why it is still used in everything from simple temperature sensors to complex PLCs.&lt;/p&gt;
&lt;p&gt;In a FlowFuse setup, the instance acts as the master, initiating all communication. Devices such as sensors, meters, and controllers act as slaves, responding only when addressed. Each slave has a unique address from 1 to 247, with 0 reserved for broadcast messages. Communication follows a simple pattern: the master sends a request, the addressed slave responds, and the master processes the response before moving to the next device.&lt;/p&gt;
&lt;h3 id=&quot;device-data-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#device-data-types&quot;&gt;Device Data Types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Devices organize data into four main types, each with a specific purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Coils (Digital Outputs)&lt;/strong&gt; – Remote switches you can turn on/off from FlowFuse, used for motors, pumps, relays, or alarms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discrete Inputs (Digital Inputs)&lt;/strong&gt; – Read-only status points that indicate the state of buttons, doors, or alarms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Registers (Analog Inputs)&lt;/strong&gt; – Read-only values representing measurements such as temperature, pressure, or flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Holding Registers (Analog Outputs/Settings)&lt;/strong&gt; – Read/write values for setpoints, timers, and configuration parameters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Coils and discrete inputs are single-bit (ON/OFF), while registers store 16-bit values that may require scaling depending on the device.&lt;/p&gt;
&lt;h3 id=&quot;register-addressing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#register-addressing&quot;&gt;Register Addressing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Addressing can be confusing because manufacturers document it differently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero-based&lt;/strong&gt; – Modbus standard (first register = 0).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One-based&lt;/strong&gt; – Some manuals start counting at 1 (subtract 1 in FlowFuse).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Offset-based&lt;/strong&gt; – Registers like 40001 or 30001 require subtracting the base number to get the actual address.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; If a manual shows “Temperature = 40001,” FlowFuse should use address &lt;strong&gt;0&lt;/strong&gt;. Always refer to the device’s “Register Map” for clarity.&lt;/p&gt;
&lt;p&gt;By understanding the &lt;strong&gt;master-slave control, data types, and addressing&lt;/strong&gt;, you can reliably communicate with your devices and make the most of Modbus RTU in FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s start by setting up the basics before connecting Modbus RTU devices to FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before diving in, make sure you have the following ready:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node-RED instance&lt;/strong&gt; – A running Node-RED instance. The quickest way to get one ready for production is with FlowFuse. Simply &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;create and set up a remote instance&lt;/a&gt;, and you’ll have a managed Node-RED environment running in minutes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Modbus nodes&lt;/strong&gt; – Installable via the Palette Manager (&lt;code&gt;node-red-contrib-modbus&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modbus-enabled device&lt;/strong&gt; – Such as a sensor, PLC, or meter, along with its register map documentation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serial interface&lt;/strong&gt; – For example, a USB-to-RS485 converter to physically connect your Modbus devices. Connect the &lt;strong&gt;A (+)&lt;/strong&gt; and &lt;strong&gt;B (–)&lt;/strong&gt; terminals of the RS485 adapter to the device, add termination resistors if the line is long or has multiple devices, and note the serial port path (e.g., &lt;code&gt;/dev/ttyUSB0&lt;/code&gt; on Linux or &lt;code&gt;COM1&lt;/code&gt; on Windows).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;reading-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#reading-data&quot;&gt;Reading Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reading data from Modbus slaves in FlowFuse is straightforward. The process is the same regardless of which data type you want to read.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Modbus Read&lt;/strong&gt; node onto the FlowFuse canvas. Double-click it to open the configuration. Enter the &lt;strong&gt;Unit ID&lt;/strong&gt; (slave address), select the &lt;strong&gt;data type&lt;/strong&gt; you want to read, specify the &lt;strong&gt;starting address&lt;/strong&gt;, set the &lt;strong&gt;quantity&lt;/strong&gt; of values to read, and define the &lt;strong&gt;poll rate&lt;/strong&gt; (how often data should be read).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Modbus Read node configured to read data from a slave device.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-read.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Modbus Read node configured to read data from a slave device.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;+&lt;/strong&gt; icon next to the &lt;em&gt;Server&lt;/em&gt; field to add Modbus connection details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the server configuration window:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;strong&gt;Type&lt;/strong&gt; to &lt;em&gt;Serial&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Serial Port&lt;/strong&gt; field, use the dropdown or search option to see all available ports (e.g., &lt;code&gt;/dev/ttyUSB0&lt;/code&gt; on Linux or &lt;code&gt;COM1&lt;/code&gt; on Windows). Select the port to which your Modbus device is connected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the communication settings to match your device:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Baud Rate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Bits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop Bits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parity&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These values must match exactly with the Modbus device’s configuration; otherwise, the communication will fail.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Serial port and communication settings for the Modbus device.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Serial port and communication settings for the Modbus device.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Connect the Modbus Read node to a &lt;strong&gt;Debug&lt;/strong&gt; node and deploy your flow. If everything is set up correctly, you will start seeing live data from your Modbus device in the debug sidebar.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;writing-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#writing-data&quot;&gt;Writing Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus RTU allows you to &lt;strong&gt;write data back to devices&lt;/strong&gt;, enabling control of motors, relays, setpoints, and other outputs directly from FlowFuse.&lt;/p&gt;
&lt;p&gt;Follow these steps to configure and test writing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Modbus Write&lt;/strong&gt; node onto the canvas. This node will send data to your Modbus device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node and set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unit ID&lt;/strong&gt; – the slave address of your device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data type&lt;/strong&gt; – choose one of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Force Single Coil&lt;/em&gt; – write one digital output.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Force Multiple Coils&lt;/em&gt; – write several digital outputs at once.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Preset Single Register&lt;/em&gt; – write one analog/config value.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Force Multiple Registers&lt;/em&gt; – write several analog values at once.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Address&lt;/strong&gt; – the target coil or register.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quantity&lt;/strong&gt; – only for multiple writes, set the number of values you will send.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Writing a single coil using the Modbus Write node.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/write-single-coil.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Writing a single coil using the Modbus Write node.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Writing multiple coils using the Modbus Write node.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/write-multi-coils.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Writing multiple coils using the Modbus Write node.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect an &lt;strong&gt;Inject&lt;/strong&gt; node to the Modbus Write node to send values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single Coil/Register:&lt;/strong&gt; send a boolean (&lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt;) for coils or a number for registers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple Coils/Registers:&lt;/strong&gt; send an array corresponding to each value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[true, false, true]&lt;/code&gt; → Coils 0, 1, 2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[25, 50, 75]&lt;/code&gt; → Holding Registers 0, 1, 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and press &lt;strong&gt;Inject&lt;/strong&gt;. The Modbus device should update immediately.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Use a &lt;strong&gt;UI input (slider, switch, or numeric box)&lt;/strong&gt; from the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; instead of an Inject node for real-time control via a web interface.&lt;/p&gt;
&lt;h2 id=&quot;scaling-and-interpreting-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#scaling-and-interpreting-values&quot;&gt;Scaling and Interpreting Values&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Raw Modbus values often don’t make sense until you apply &lt;strong&gt;scaling factors&lt;/strong&gt; or unit conversions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A temperature register might return &lt;code&gt;235&lt;/code&gt;, which actually means &lt;strong&gt;23.5 °C&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An energy meter might output &lt;code&gt;12345&lt;/code&gt;, representing &lt;strong&gt;12.345 kWh&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A pressure sensor could use two consecutive registers (32-bit values) that need decoding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can handle these conversions with simple &lt;strong&gt;Function nodes&lt;/strong&gt; or &lt;strong&gt;Change nodes&lt;/strong&gt; in FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example Function Node:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-329&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-329&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Convert raw register value to temperature in °C&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; raw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; raw &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-329&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This takes the raw register, divides it by 10, and gives you a clean, human-readable temperature.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You do not need to know JavaScript — simply use the &lt;strong&gt;FlowFuse Expert&lt;/strong&gt;, which can generate a Function node for you from plain English instructions. For the most accurate results, provide sample data along with the scaling you want to achieve. You can learn more in this article: &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse Expert for Manufacturing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best Practice:&lt;/strong&gt; Always keep a copy of the device’s &lt;strong&gt;Register Map documentation&lt;/strong&gt; handy. It tells you which addresses map to which variables, and how to interpret them.&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting-tips&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#troubleshooting-tips&quot;&gt;Troubleshooting Tips&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If things do not work on the first attempt, avoid frustration. Modbus is straightforward, but even small configuration mismatches can disrupt communication.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify the &lt;strong&gt;serial port&lt;/strong&gt; is correct and not already in use.&lt;/li&gt;
&lt;li&gt;Double-check &lt;strong&gt;baud rate, data bits, stop bits, and parity&lt;/strong&gt;. Even a single mismatch will block communication.&lt;/li&gt;
&lt;li&gt;Ensure the &lt;strong&gt;Unit ID&lt;/strong&gt; matches your device’s slave address.&lt;/li&gt;
&lt;li&gt;Keep your wiring neat. For longer cables, use &lt;strong&gt;termination resistors&lt;/strong&gt; and twisted-pair shielded cables.&lt;/li&gt;
&lt;li&gt;Use a Modbus simulator or diagnostic tool to test the setup if the hardware isn’t responding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/using-modbus-with-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus RTU has stood the test of time in industrial automation because it’s simple, reliable, and built for harsh environments. With FlowFuse, you can take this legacy protocol and give it &lt;strong&gt;modern superpowers&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collect real-time data from sensors and machines.&lt;/li&gt;
&lt;li&gt;Control devices directly from a web dashboard.&lt;/li&gt;
&lt;li&gt;Combine Modbus with MQTT, REST APIs, or databases to share data across your entire organization.&lt;/li&gt;
&lt;li&gt;Scale from a single sensor to a &lt;strong&gt;factory-wide monitoring and control system&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The real value comes when you stop treating Modbus as just a communication protocol and start using FlowFuse as the &lt;strong&gt;bridge between industrial devices and enterprise systems&lt;/strong&gt;. From dashboards to alerts, from analytics to cloud integration — the possibilities are endless once the data is in your hands.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/what-is-takt-time/</id>
        <title>Takt Time: Definition, Formula, How to Calculate with Examples &amp; More [2026 Edition]</title>
        <summary>Master takt time to synchronize production with customer demand using lean manufacturing principles</summary>
        <updated>2025-09-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/what-is-takt-time/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Takt time is one of the most fundamental—and most misunderstood—concepts in lean manufacturing. Despite being widely referenced in textbooks, audits, and production meetings, many factories still calculate takt time incorrectly or treat it as a theoretical number rather than an operational control. The result is familiar: overproduction during low demand, missed deliveries during peak demand, unstable lines, and constant firefighting on the shop floor.&lt;/p&gt;
&lt;p&gt;In reality, &lt;strong&gt;takt time is not a KPI—it is a design constraint&lt;/strong&gt;. It defines the exact pace at which a production system must operate to meet real customer demand using the available working time. When applied correctly, takt time becomes the backbone of flow, line balancing, capacity planning, and continuous improvement. When applied incorrectly, it creates false confidence, hidden bottlenecks, and chronic inefficiencies.&lt;/p&gt;
&lt;p&gt;This guide is written from a &lt;strong&gt;practical, factory-floor perspective&lt;/strong&gt;, not just a theoretical lean framework. It reflects how takt time is actually used in modern manufacturing environments—automotive plants, electronics assembly lines, FMCG production, and digitally connected factories running real-time systems. Every definition, formula, and example in this article is grounded in how takt time is applied by production engineers, operations managers, and lean practitioners to solve real problems.&lt;/p&gt;
&lt;p&gt;In this 2026 edition, you’ll learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The correct definition of takt time and what it truly represents operationally&lt;/li&gt;
&lt;li&gt;How to calculate takt time accurately, including what time must be excluded (and why)&lt;/li&gt;
&lt;li&gt;The difference between takt time, cycle time, and lead time, and how confusing them leads to bad decisions&lt;/li&gt;
&lt;li&gt;Real-world examples showing how takt time exposes bottlenecks and capacity gaps&lt;/li&gt;
&lt;li&gt;How modern digital tools calculate and monitor takt time in real time, not spreadsheets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether you are designing a new production line, stabilizing an existing process, or transitioning toward lean and Industry 4.0 practices, this guide gives you a complete, trustworthy, and experience-backed explanation of takt time, from first principles to real-world execution.&lt;/p&gt;
&lt;h2 id=&quot;what-is-takt-time%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#what-is-takt-time%3F&quot;&gt;What is Takt Time?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Takt time&lt;/strong&gt; is the maximum allowable time to produce one unit of product to meet customer demand. It acts as the &amp;quot;heartbeat&amp;quot; of your production line, establishing the rhythm at which work must flow to satisfy customer orders without overproducing or falling behind.&lt;/p&gt;
&lt;p&gt;The word &amp;quot;takt&amp;quot; derives from the German word &amp;quot;taktzeit,&amp;quot; which translates to &amp;quot;cycle time&amp;quot; or &amp;quot;beat.&amp;quot; This linguistic origin reflects the concept&#39;s European manufacturing heritage, though it&#39;s important to recognize that takt time and cycle time represent fundamentally different metrics. We&#39;ll examine this critical distinction in detail later in this guide.&lt;/p&gt;
&lt;h3 id=&quot;formal-definition-of-takt-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#formal-definition-of-takt-time&quot;&gt;Formal Definition of Takt Time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;definition of takt time&lt;/strong&gt; is: the available production time divided by customer demand. This establishes the pace at which your production line must operate to meet customer requirements. It&#39;s a customer-driven metric calculated from actual demand rather than production capability.&lt;/p&gt;
&lt;p&gt;Takt time serves as both a planning tool and a mechanism for waste elimination, providing a common reference point for distributing work evenly across production stations.&lt;/p&gt;
&lt;h3 id=&quot;meaning-of-takt-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#meaning-of-takt-time&quot;&gt;Meaning of Takt Time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;meaning of takt time&lt;/strong&gt; goes deeper than just a calculation—it represents your production heartbeat. It&#39;s the pulse that synchronizes all production activities with real customer demand.&lt;/p&gt;
&lt;p&gt;The operational meaning of takt time functions as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A planning target that prevents overproduction and underproduction&lt;/li&gt;
&lt;li&gt;A balancing tool that distributes work evenly across workstations&lt;/li&gt;
&lt;li&gt;A performance metric that reveals bottlenecks and capacity constraints&lt;/li&gt;
&lt;li&gt;A continuous improvement baseline that quantifies the gap between current and required performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you properly understand what takt time means, you transform it from a simple formula into a powerful operational philosophy that drives lean manufacturing excellence.&lt;/p&gt;
&lt;h2 id=&quot;takt-time-formula&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#takt-time-formula&quot;&gt;Takt Time Formula&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Takt Time Formula&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/takt-time-formula.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The fundamental takt time formula&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;takt time formula&lt;/strong&gt; is deceptively simple, yet its application transforms manufacturing operations:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takt Time = Available Production Time ÷ Customer Demand&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This &lt;strong&gt;formula of takt time&lt;/strong&gt; contains two critical components that require careful definition. Let&#39;s break down each element to understand how to calculate takt time accurately.&lt;/p&gt;
&lt;h3 id=&quot;available-production-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#available-production-time&quot;&gt;Available Production Time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the net time available for production during your planning period (typically one shift or one day). When applying the takt formula, available production time includes only planned production time. It excludes planned breaks, meetings, shift changes, and scheduled maintenance, but does not include unplanned downtime such as breakdowns or minor stoppages. It excludes scheduled breaks and lunch periods, shift changeovers, planned maintenance windows, and scheduled meetings or training.&lt;/p&gt;
&lt;p&gt;Consider an example calculation of takt time. An eight-hour shift equals 480 minutes. Subtract a 10-minute break to yield 470 minutes. Subtract a 20-minute lunch to yield 450 minutes. Subtract a 30-minute planned changeover to yield 420 minutes. The available production time equals 420 minutes.&lt;/p&gt;
&lt;p&gt;The distinction between included and excluded time proves critical for accurate takt time calculation. Organizations frequently overestimate available time by failing to account for all legitimate non-production activities, then face persistent schedule shortfalls when reality proves less generous than planning assumptions.&lt;/p&gt;
&lt;h3 id=&quot;customer-demand&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#customer-demand&quot;&gt;Customer Demand&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you calculate takt time, customer demand represents the number of units customers require during your planning period. This figure can derive from actual customer orders, forecasted demand, production targets based on inventory levels, or averaged demand over longer periods such as weeks or months.&lt;/p&gt;
&lt;p&gt;The choice of demand figure affects the meaning of takt time stability and operational practicality. Using daily order quantities creates takt times that vary day-to-day, potentially requiring frequent line rebalancing. Averaging demand over weekly or monthly periods creates more stable takt times but may result in temporary overproduction or underproduction as actual daily demand fluctuates around the average.&lt;/p&gt;
&lt;p&gt;Most manufacturers employ hybrid approaches, using averaged demand for line design and capacity planning while adjusting targets periodically to reflect actual order patterns. The appropriate averaging period depends on demand volatility, product mix complexity, and production flexibility.&lt;/p&gt;
&lt;h3 id=&quot;calculating-takt-time%3A-a-step-by-step-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#calculating-takt-time%3A-a-step-by-step-example&quot;&gt;Calculating Takt Time: A Step-by-Step Example&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using our example numbers where available production time equals 420 minutes and customer demand equals 210 units, let&#39;s apply the takt time formula:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takt Time = 420 minutes ÷ 210 units = 2.0 minutes per unit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This result means your production line must complete one unit every 2 minutes to meet customer demand. When you define takt time this way, the calculation establishes a maximum allowable cycle time—any operation taking longer than 2 minutes per unit will prevent the line from meeting demand unless compensated by faster cycle times elsewhere or by adding capacity.&lt;/p&gt;
&lt;h2 id=&quot;real-world-examples-of-takt-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#real-world-examples-of-takt-time&quot;&gt;Real-World Examples of Takt Time&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Examining several real-world examples demonstrates how to calculate takt time across different manufacturing contexts. These examples show the practical application of the takt time formula in diverse scenarios.&lt;/p&gt;
&lt;h3 id=&quot;example-1%3A-automotive-parts-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#example-1%3A-automotive-parts-manufacturing&quot;&gt;Example 1: Automotive Parts Manufacturing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An automotive parts manufacturer produces brake assemblies during an eight-hour shift. The shift includes a 30-minute lunch period and two 10-minute breaks totaling 20 minutes. A planned changeover consumes 10 minutes. Customer orders require 120 brake assemblies per shift.&lt;/p&gt;
&lt;p&gt;To calculate takt time, first determine available production time. Start with 480 minutes for the eight-hour shift. Subtract 30 minutes for lunch, 20 minutes for breaks, and 10 minutes for changeover. The available production time equals 420 minutes.&lt;/p&gt;
&lt;p&gt;Now apply the takt time formula. Divide 420 minutes by 120 units to yield 3.5 minutes per unit.&lt;/p&gt;
&lt;p&gt;Understanding the meaning of takt time in this result shows the production line must complete one brake assembly every 3.5 minutes to meet customer demand. If actual cycle time equals 5 minutes per unit, production will fall short by approximately 30 percent, completing only 84 units instead of the required 120 units. If actual cycle time equals 3 minutes per unit, the line produces 140 units, creating 20 units of excess inventory and risking overproduction waste.&lt;/p&gt;
&lt;p&gt;This example illustrates why defining takt time correctly matters for matching cycle time to customer demand. Cycle times significantly exceeding takt time reveal capacity shortfalls requiring immediate attention. Cycle times falling well below takt time suggest excess capacity that might be redeployed elsewhere or indicate risk of overproduction if production control systems fail to prevent excess output.&lt;/p&gt;
&lt;h3 id=&quot;example-2%3A-electronics-assembly-(multiple-shifts)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#example-2%3A-electronics-assembly-(multiple-shifts)&quot;&gt;Example 2: Electronics Assembly (Multiple Shifts)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An electronics manufacturer operates two shifts producing circuit boards, with weekly demand of 2,400 units across five operating days. Each eight-hour shift allocates 40 minutes for breaks and 20 minutes for changeovers.&lt;/p&gt;
&lt;p&gt;When you calculate takt time for multiple shifts, first determine available time per shift: 480 minutes minus 40 minutes for breaks minus 20 minutes for changeovers equals 420 minutes per shift.&lt;/p&gt;
&lt;p&gt;Calculate total available time per week: 420 minutes multiplied by 2 shifts multiplied by 5 days equals 4,200 minutes per week.&lt;/p&gt;
&lt;p&gt;Apply the takt formula: 4,200 minutes divided by 2,400 units equals 1.75 minutes per unit.&lt;/p&gt;
&lt;p&gt;An alternative approach to calculate takt time uses per-shift demand. Daily demand equals 2,400 units divided by 5 days, or 480 units per day. Demand per shift equals 480 units divided by 2 shifts, or 240 units per shift. Using the takt time formula: 420 minutes divided by 240 units equals 1.75 minutes per unit—the same result.&lt;/p&gt;
&lt;p&gt;This example demonstrates that the takt time calculation can proceed from different time horizons and still yield consistent results. Whether calculating weekly, daily, or per-shift takt time using the takt formula, the fundamental relationship between available time and required output remains constant. Organizations typically choose calculation periods matching their planning cycles and demand visibility horizons.&lt;/p&gt;
&lt;h3 id=&quot;example-3%3A-variable-product-mix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#example-3%3A-variable-product-mix&quot;&gt;Example 3: Variable Product Mix&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A manufacturer produces three different models on the same production line with 450 minutes of available time. Model A requires 100 units at 2 minutes per unit, Model B requires 50 units at 3 minutes per unit, and Model C requires 30 units at 4 minutes per unit.&lt;/p&gt;
&lt;p&gt;To define takt time for mixed-model production, calculate weighted average takt time by summing total demand: 100 plus 50 plus 30 equals 180 units. Using the takt time formula, average takt time equals 450 minutes divided by 180 units, or 2.5 minutes per unit.&lt;/p&gt;
&lt;p&gt;Individual product takt times can also be calculated using the formula of takt time. Model A would receive 4.5 minutes per unit (450 divided by 100), though its actual process time is only 2 minutes. Model B would receive 9.0 minutes per unit, and Model C would receive 15.0 minutes per unit. In mixed-model production, manufacturers typically employ level loading techniques to smooth production across the shift rather than producing in large batches.&lt;/p&gt;
&lt;p&gt;Level loading for this scenario might sequence production as A-A-B-A-A-C-A-A-B-A-A-C, distributing the three models proportionally throughout available time. This sequence maintains steadier overall pace than producing all Model A units first, then all Model B units, then all Model C units. Understanding the meaning of takt time in this context shows how steady pace reduces work-in-process buildup, makes quality problems visible sooner, and creates more predictable material consumption patterns.&lt;/p&gt;
&lt;h2 id=&quot;takt-time-vs.-cycle-time-vs.-lead-time%3A-comparison-matrix&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#takt-time-vs.-cycle-time-vs.-lead-time%3A-comparison-matrix&quot;&gt;Takt Time vs. Cycle Time vs. Lead Time: Comparison Matrix&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You might have heard the terms takt time, cycle time, and lead time, but they&#39;re not the same. Let&#39;s define takt time and these related metrics to understand their distinct meanings.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Takt Time&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cycle Time&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Lead Time&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fundamental Meaning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The &amp;quot;Heartbeat.&amp;quot; The pace required to satisfy the customer.&lt;/td&gt;
&lt;td&gt;The &amp;quot;Actual Speed.&amp;quot; The time it takes to perform the work.&lt;/td&gt;
&lt;td&gt;The &amp;quot;Wait Time.&amp;quot; The total duration a part spends in the system.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Formula&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Available Production Time ÷ Customer Demand&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Time to complete one unit of work&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Order completion time – Order placement time&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it Includes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only net available production time (no breaks).&lt;/td&gt;
&lt;td&gt;Loading, processing, unloading, and reset time.&lt;/td&gt;
&lt;td&gt;Processing time + Queue time + Shipping + Delays.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Planning:&lt;/strong&gt; How many people or machines do we need?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Efficiency:&lt;/strong&gt; How can we make this specific task faster?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Responsiveness:&lt;/strong&gt; How quickly can we turn an order into cash?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Management Signal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If this changes, you must rebalance your production line.&lt;/td&gt;
&lt;td&gt;If this is too high, you have a bottleneck at that station.&lt;/td&gt;
&lt;td&gt;If this is too high, your inventory levels are likely bloated.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;the-%22ideal-state%22-relationship&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#the-%22ideal-state%22-relationship&quot;&gt;The &amp;quot;Ideal State&amp;quot; Relationship&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a perfect Lean environment, the relationship between these three metrics follows a hierarchy that maximizes ROI and eliminates waste. When you properly calculate takt time and understand its meaning, the ideal relationships emerge:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cycle Time ≤ Takt Time:&lt;/strong&gt; Your actual work speed should be roughly &lt;strong&gt;90–95% of Takt Time&lt;/strong&gt;, providing a small buffer for minor interruptions without failing to meet customer demand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimized Lead Time:&lt;/strong&gt; Lead Time should be as close as possible to the sum of your Cycle Times. For example, if total Cycle Time is 1 hour but Lead Time is 10 days, &lt;strong&gt;99% of the product&#39;s time is idle&lt;/strong&gt;, representing pure waste.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;why-takt-time-matters-in-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#why-takt-time-matters-in-manufacturing&quot;&gt;Why Takt Time Matters in Manufacturing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding the definition of takt time and applying the takt formula functions as more than a calculation exercise. It represents a fundamental operating principle that transforms manufacturing execution from reactive scheduling to demand-synchronized production.&lt;/p&gt;
&lt;h3 id=&quot;synchronization-with-customer-demand&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#synchronization-with-customer-demand&quot;&gt;Synchronization with Customer Demand&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Production systems operating without understanding what takt time means typically run at maximum achievable speed, independent of actual demand signals. This approach generates inventory during periods of low demand and creates capacity shortages when demand increases. The disconnect between production pace and order rate leads to resource misallocation and suboptimal working capital deployment.&lt;/p&gt;
&lt;p&gt;When you define takt time and apply it correctly, you establish direct alignment between order rate and production pace. When demand changes, the calculated takt time changes proportionally using the takt time formula, triggering controlled adjustments to production resources. This synchronization maintains lean inventory levels while meeting delivery commitments.&lt;/p&gt;
&lt;h3 id=&quot;elimination-of-overproduction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#elimination-of-overproduction&quot;&gt;Elimination of Overproduction&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Overproduction amplifies other forms of manufacturing waste. Excess production requires additional handling, consumes storage capacity, ties up working capital, and increases the inventory at risk from quality issues or obsolescence. Organizations often underestimate the compounding effect of overproduction on total manufacturing cost.&lt;/p&gt;
&lt;p&gt;The meaning of takt time in waste elimination establishes a maximum production rate derived from actual demand. Production exceeding the rate calculated using the takt formula generates inventory that customer orders have not yet justified. Pull-based production systems use takt time as the foundation for inventory replenishment signals, preventing unauthorized production while maintaining buffer stock at calculated levels.&lt;/p&gt;
&lt;h3 id=&quot;line-balancing-and-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#line-balancing-and-flow&quot;&gt;Line Balancing and Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Manufacturing lines develop bottlenecks when workstation cycle times vary significantly. Slow stations create waiting at downstream operations, fast stations create waiting at upstream operations, and both conditions generate work-in-process inventory that obscures quality issues and extends lead time.&lt;/p&gt;
&lt;p&gt;When you calculate takt time and apply it to each workstation, you provide a common target for balancing workload across all stations. When each station operates near the calculated takt time, flow improves and waiting decreases. Line balancing efforts use the takt time formula as the reference point for redistributing work elements across stations.&lt;/p&gt;
&lt;p&gt;Consider a three-station line before balancing. Station 1 completes work in 1.5 minutes, Station 2 requires 3.5 minutes, and Station 3 completes in 2.0 minutes. The bottleneck at Station 2 limits throughput while Stations 1 and 3 accumulate idle time. After balancing to a 2.5-minute takt time (calculated using the takt formula), Station 1 performs work totaling 2.3 minutes, Station 2 completes 2.4 minutes of work, and Station 3 handles 2.3 minutes. Flow improves and bottleneck waiting largely disappears.&lt;/p&gt;
&lt;h3 id=&quot;resource-planning-and-capacity-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#resource-planning-and-capacity-analysis&quot;&gt;Resource Planning and Capacity Analysis&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The takt time formula quantifies the relationship between demand and required capacity. When cycle time exceeds the calculated takt time, analysis immediately reveals whether additional operators, additional shifts, faster equipment, or process improvement can close the gap. When cycle time falls well below takt time, excess capacity becomes visible and can be redeployed.&lt;/p&gt;
&lt;p&gt;Staffing requirements derive from the comparison between takt time and cycle time. Equipment investment decisions gain quantitative support when takt time analysis demonstrates that current equipment cannot achieve required cycle times. Capacity planning validates whether demand projections require facility expansion or whether existing assets suffice.&lt;/p&gt;
&lt;h3 id=&quot;continuous-improvement-framework&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#continuous-improvement-framework&quot;&gt;Continuous Improvement Framework&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you define takt time clearly, it establishes a baseline for improvement initiatives. The gap between current cycle time and required takt time (calculated using the takt time formula) quantifies the improvement target. Kaizen events and process optimization efforts use this gap to prioritize activities and measure progress.&lt;/p&gt;
&lt;p&gt;The improvement cycle follows a standard pattern. Measure current cycle time and compare to calculated takt time. Identify root causes for the gap. Implement improvements addressing these causes. Validate the new cycle time against the takt formula results. Document the process and repeat. This structured approach replaces ad hoc improvement with systematic capability building.&lt;/p&gt;
&lt;h3 id=&quot;quality-and-safety-considerations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#quality-and-safety-considerations&quot;&gt;Quality and Safety Considerations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Operating at sustainable pace rather than maximum speed affects both quality outcomes and safety performance. Production systems pushed to maximum throughput often sacrifice quality checks, proper technique, and ergonomic considerations. The pressure to maintain speed creates conditions where errors multiply and injuries occur.&lt;/p&gt;
&lt;p&gt;Understanding the true meaning of takt time shows it&#39;s about sustainable pace. Takt time–based production (properly calculated using the takt formula) operates at a pace that supports proper work methods, allows time for quality verification at each station, and reduces the physical stress associated with rushing. Manufacturing operations report substantial reductions in defects when transitioning from maximum-speed production to takt time–based production. Similarly, safety incident rates decline when operators work at a sustainable pace rather than pushing to maximum achievable speed.&lt;/p&gt;
&lt;h2 id=&quot;implementing-takt-time-monitoring-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#implementing-takt-time-monitoring-with-flowfuse&quot;&gt;Implementing Takt Time Monitoring with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While understanding the theory behind the definition of takt time is important, putting it into practice requires the right tools and approach. &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; provides an industrial automation platform that connects to your existing systems—whether that&#39;s &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/&quot;&gt;PLCs&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/node-red/database/&quot;&gt;databases&lt;/a&gt;, or ERP software—to automatically calculate takt time in real-time using the takt time formula.&lt;/p&gt;
&lt;p&gt;Instead of manually calculating takt time on spreadsheets or relying on static reports, you can build a dynamic monitoring system that updates continuously as customer orders and production conditions change. Let&#39;s see how to calculate takt time automatically, but before we begin, make sure you have a FlowFuse instance running. You can &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;create an account here&lt;/a&gt; and get it set up quickly.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-connect-to-your-data-sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#step-1%3A-connect-to-your-data-sources&quot;&gt;Step 1: Connect to Your Data Sources&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The foundation of accurate takt time calculation is reliable data. FlowFuse supports connections to virtually any industrial system through its extensive library of &lt;a href=&quot;https://flowfuse.com/node-red/protocol/&quot;&gt;protocol&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/node-red/database/&quot;&gt;database&lt;/a&gt; nodes.&lt;/p&gt;
&lt;p&gt;In a real implementation where you define takt time based on actual operations, you would pull customer order data from your ERP system, gather production schedules from manufacturing execution systems, connect to PLCs for real-time production counts, and integrate with quality systems for good parts tracking. You can &lt;a href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/&quot;&gt;pull customer order data from your ERP system&lt;/a&gt; using FlowFuse&#39;s integration capabilities.&lt;/p&gt;
&lt;p&gt;For this demonstration of how to calculate takt time, we&#39;ll simulate customer orders using an Inject node:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add an Inject node&lt;/li&gt;
&lt;li&gt;Configure the payload with this JSONata expression:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-415&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-415&quot; class=&quot;language-json&quot;&gt;   $round($random() * &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt; + &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-415&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Set it to trigger every 5 seconds&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This simulates variability in customer demand between 50 and 100 units, demonstrating how the takt time formula responds to changing demand.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-calculate-available-production-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#step-2%3A-calculate-available-production-time&quot;&gt;Step 2: Calculate Available Production Time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, establish the available production time for your shift—a critical component when you calculate takt time. This typically equals your total shift hours minus planned downtime for breaks, maintenance, and changeovers.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a Change node&lt;/li&gt;
&lt;li&gt;Use the following JSONata expression:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-444&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-444&quot; class=&quot;language-json&quot;&gt;   (&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt; * &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;) - &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-444&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This represents an 8-hour shift (480 minutes) minus 1 hour (60 minutes) for breaks and changeovers, giving 420 minutes of available production time—the numerator in the takt time formula.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-automate-takt-time-calculation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#step-3%3A-automate-takt-time-calculation&quot;&gt;Step 3: Automate Takt Time Calculation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, apply the takt formula to calculate takt time based on customer demand and available time.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add another Change node&lt;/li&gt;
&lt;li&gt;Configure it with this JSONata expression:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-466&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-466&quot; class=&quot;language-json&quot;&gt;   $round(($number(msg.payload.availableTime) / $number(msg.payload.customer_order)) * &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;)/&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-466&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This implements the takt time formula automatically: Available Production Time ÷ Customer Demand. The calculation ensures takt time updates dynamically with each new order and produces clean, readable numbers for operators and managers.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-create-real-time-dashboards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#step-4%3A-create-real-time-dashboards&quot;&gt;Step 4: Create Real-Time Dashboards&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Data is most valuable when operators can interpret the meaning of takt time instantly on the shop floor. FlowFuse&#39;s dashboard lets you create real-time displays showing calculated takt time using the same intuitive drag-and-drop interface.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;a href=&quot;https://flowfuse.com/platform/dashboard/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; package via the Palette Manager (&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;For basic displays, use text widgets to show current takt time values calculated using the takt formula. For more sophisticated interfaces, the Template widget allows you to create custom components. With &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;FlowFuse AI&lt;/a&gt;, you can describe your desired interface in plain English and let the AI generate the appropriate code&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the Change node that calculates available production time. Next, connect the output of this Change node to the input of the Change node that calculates takt time using the formula. Finally, connect the output of the takt time Change node to the input of the UI Template node&lt;/li&gt;
&lt;li&gt;Next, deploy the flow and open the dashboard to see real-time takt time updates&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Simple takt time display dashboard built with FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/takt-time-flowfuse.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Real-time takt time monitoring dashboard in FlowFuse showing the takt formula in action&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s the complete flow we built for automated takt time calculation and visualization with FlowFuse, demonstrating how to calculate takt time in real-time.&lt;/p&gt;
&lt;div id=&quot;nr-flow-246&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow246 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d5e580f48a9299a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c2c694c911f786fe&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulate Customer Order&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.customer_order&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;$round($random() * 50 + 50)&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;518dbc1ac72f7c21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;518dbc1ac72f7c21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c2c694c911f786fe&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Calculate total available time&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.availableTime&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;(8 * 60) - 60&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3d35535dbb06fc86&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3d35535dbb06fc86&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c2c694c911f786fe&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Calculate Takt Time&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$round(($number(msg.payload.availableTime) / $number(msg.payload.customer_order)) * 100)/100&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:910,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;de044b9204a9b248&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de044b9204a9b248&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c2c694c911f786fe&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;79d59adc1e8219b7&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display: Takt Time&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n  &amp;lt;v-sheet class=&#92;&#92;&#92;&quot;d-flex justify-center align-center led-background&#92;&#92;&#92;&quot; height=&#92;&#92;&#92;&quot;150&#92;&#92;&#92;&quot; elevation=&#92;&#92;&#92;&quot;4&#92;&#92;&#92;&quot; rounded&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;led-display&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n  &amp;lt;/v-sheet&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;script&amp;gt;&#92;&#92;n  export default {&#92;&#92;n  data() {&#92;&#92;n    return {&#92;&#92;n      taktTime: this.msg?.payload ?? &#39;00:00.0&#39;&#92;&#92;n    }&#92;&#92;n  },&#92;&#92;n  watch: {&#92;&#92;n    msg(newMsg) {&#92;&#92;n      if (newMsg?.payload) {&#92;&#92;n        this.taktTime = newMsg.payload;&#92;&#92;n      }&#92;&#92;n    }&#92;&#92;n  }&#92;&#92;n}&#92;&#92;n&amp;lt;/script&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;style scoped&amp;gt;&#92;&#92;n  .led-background {&#92;&#92;n    background: #0a0a0a;&#92;&#92;n    /* Dark black background */&#92;&#92;n    background-image: radial-gradient(circle, #111 1px, #0a0a0a 1px);&#92;&#92;n    background-size: 20px 20px;&#92;&#92;n    /* Carbon-like grid */&#92;&#92;n  }&#92;&#92;n&#92;&#92;n  .led-display {&#92;&#92;n    font-family: &#39;Digital-7&#39;, monospace;&#92;&#92;n    font-size: 96px;&#92;&#92;n    color: #0f0;&#92;&#92;n    text-shadow:&#92;&#92;n      0 0 5px #0f0,&#92;&#92;n      0 0 10px #0f0,&#92;&#92;n      0 0 20px #0f0,&#92;&#92;n      0 0 30px #0f0;&#92;&#92;n  }&#92;&#92;n&amp;lt;/style&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;!-- Include Digital-7 font from CDN --&amp;gt;&#92;&#92;n&amp;lt;link href=&#92;&#92;&#92;&quot;https://fonts.googleapis.com/css2?family=Orbitron&amp;amp;display=swap&#92;&#92;&#92;&quot; rel=&#92;&#92;&#92;&quot;stylesheet&#92;&#92;&#92;&quot;&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;79d59adc1e8219b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Takt Time&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;9b1c640ccc6a665e&#92;&quot;,&#92;&quot;width&#92;&quot;:6,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;9b1c640ccc6a665e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;FlowFuse Dashboard&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;d44eab3a91dda8d9&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;2278e18670b606b7&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;d44eab3a91dda8d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;2278e18670b606b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#2e073e&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;da2b78557435736b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.27.2&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow246.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-246&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;best-practices-for-takt-time-implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#best-practices-for-takt-time-implementation&quot;&gt;Best Practices for Takt Time Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you understand how to define takt time and apply the takt time formula correctly, implementation success depends on following proven best practices. The meaning of takt time only translates to operational excellence when these principles guide your approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accurate Data:&lt;/strong&gt; Base your takt time calculation on actual production time, including breaks, changeovers, maintenance, and realistic downtime. Use real customer demand when applying the takt formula and update regularly to maintain accuracy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Leadership Commitment:&lt;/strong&gt; Leaders must support implementation visibly, allocate resources, participate in training, and communicate the benefits clearly. Understanding the takt time starts at the top.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gradual Deployment:&lt;/strong&gt; Start with a pilot line where you can define takt time clearly, train operators thoroughly, stabilize each phase, and expand gradually. Avoid implementing the takt time across all lines at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lean Integration:&lt;/strong&gt; Combine takt time (calculated using the proper formula) with value stream mapping, standardized work, and 5S to reduce waste and improve process capability. The meaning of takt time is amplified when integrated with other lean tools.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Visual Management:&lt;/strong&gt; Use intuitive, visible displays that show calculated takt time and production status at a glance, enabling quick operator action when cycle times exceed the takt time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Problem Response:&lt;/strong&gt; Establish escalation procedures, maintain critical spares, station maintenance nearby, and train operators in basic troubleshooting. Quick response preserves the production pace defined by takt time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Continuous Refinement:&lt;/strong&gt; Review takt time calculations regularly, analyze performance trends against calculated takt time, and share lessons learned to improve future deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-takt-time/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The true meaning of takt time goes far beyond a simple calculation—it&#39;s the essential &amp;quot;heartbeat&amp;quot; of lean manufacturing that transforms volatile customer demand into a precise, manageable production rhythm. When you properly define takt time and apply the takt time formula consistently, you expose bottlenecks, balance workloads, and create predictable flow that maximizes resource utilization.&lt;/p&gt;
&lt;p&gt;While the &lt;strong&gt;takt formula&lt;/strong&gt; (Takt Time = Available Production Time ÷ Customer Demand) is mathematically simple, its implementation is what separates world-class operations from those plagued by overproduction and constant firefighting. Understanding how to calculate takt time accurately and what the definition of takt time truly means operationally allows you to synchronize your production pace with the market.&lt;/p&gt;
&lt;p&gt;By learning to define takt time properly and applying the takt time formula in the right contexts, you expose bottlenecks, balance workloads, and create a predictable flow that maximizes resource utilization. However, manual tracking often leads to lagging data and missed opportunities. Modern industrial platforms like &lt;strong&gt;FlowFuse&lt;/strong&gt; bridge this gap, providing the real-time visibility needed to monitor Takt Time, Cycle Time, and Lead Time automatically across your entire value stream.&lt;/p&gt;
&lt;p&gt;Mastering takt time isn&#39;t about working faster—it&#39;s about working at the right pace. When production is synchronized with demand, every minute on the shop floor creates customer value instead of waste. When you truly understand what it means to define takt time and calculate takt time correctly using the proper formula, you unlock the foundation of lean manufacturing excellence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book your demo&lt;/a&gt; today to see how FlowFuse can automate your production metrics and help you eliminate waste through real-time data visibility.&lt;/strong&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/</id>
        <title>FlowFuse 2.22: FlowFuse Expert for node editing, FlowFuse Broker schema autodetection, Improved Snapshots Interface, eCharts enablement, and FlowFuse Dashboard Updates</title>
        <summary>FlowFuse Expert for node editing, FlowFuse Broker schema autodetection, Improved Snapshots Interface, eCharts enablement, and FlowFuse Dashboard Updates</summary>
        <updated>2025-09-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.22 provides more powerful development by bringing the FlowFuse Assistant to more nodes, supports operational maturity with automatic FlowFuse Broker schema detection, and enhances the developer experience with an improved Snapshots interface, support for more powerful visualizations, a better Device Agent Installer experience, Dashboard updates, and more! Take a look:&lt;/p&gt;
&lt;h2 id=&quot;ai-expert-for-node-editing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#ai-expert-for-node-editing&quot;&gt;AI Expert for Node Editing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Gif showing FlowFuse Expert in Function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/inline-assist-function.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert at work&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve enhanced the capabilities of the FlowFuse Expert, which now provides automatic suggestions to draft and edit your code that extends to Tables nodes, Dashboard Template nodes (ui-template), and Function nodes. You can now simply start typing, and the FlowFuse Assistant will provide code for you based on your context, making the FlowFuse Assistant your AI copilot in Node-RED.&lt;/p&gt;
&lt;p&gt;With this change, the FlowFuse assistant can now write HTML, CSS, SQL, Javascript, and JSON, all based on your words, and with awareness of your FlowFuse environment (like your Tables structure), cursor position, and where in your code you are editing.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-team-broker-automatic-schema-detection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#flowfuse-team-broker-automatic-schema-detection&quot;&gt;FlowFuse Team Broker Automatic Schema Detection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image showing schema detection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/schema-autodetect.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Enable schema autodetection for FlowFuse Broker&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Documenting a broker schema can be a challenging and time-consuming task, which is why we&#39;ve provided schema autodetection for the FlowFuse Broker. With the click of a button, our broker will now listen for topics and provide suggestions for the topic schema that you can accept or revise, and these will be added to documentation for your broker.&lt;/p&gt;
&lt;p&gt;This will keep your team aligned on message format and serve as a single source of truth for maintaining your Unified Namespace.&lt;/p&gt;
&lt;h2 id=&quot;enablement-for-apache-echarts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#enablement-for-apache-echarts&quot;&gt;Enablement for Apache eCharts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With this release, we are now positioned to enable much more powerful and visually-compelling charts to FlowFuse Dashboard, and have significantly increased chart performance.&lt;/p&gt;
&lt;p&gt;We&#39;ve enabled the use of Apache eCharts. It used to take 8.3 seconds to render 1,000 data points, and now it takes 75 milliseconds -- that is about 111 times faster performance!&lt;/p&gt;
&lt;p&gt;While the primary work for Apache eCharts has been to enable the addition of new chart types, we did add one new type of chart: categorical line charts.&lt;/p&gt;
&lt;p&gt;Which charts would you like to see added first? &lt;a href=&quot;https://echarts.apache.org/examples/en/index.html&quot;&gt;Check out these examples of what is now possible&lt;/a&gt;, and reach out on &lt;a href=&quot;https://github.com/flowfuse/node-red-dashboard&quot;&gt;GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;updated-snapshots-ui&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#updated-snapshots-ui&quot;&gt;Updated Snapshots UI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image of updated Snapshots user interface&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshots-ui.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Manage Snapshots in the new panel&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Snapshots are now much easier to manage and interact with.&lt;/p&gt;
&lt;p&gt;The Snapshots user interface now provides a centralized place to manage your snapshots, providing a preview of the snapshot, download options, restore, edit name and description, and compare to other snapshots, all in one easy-to-manage location in the right side of the interface.&lt;/p&gt;
&lt;p&gt;While the features available for managing Snapshots remain, this update brings those features to the surface in a much cleaner and more intuitive way.&lt;/p&gt;
&lt;h2 id=&quot;remote-instance-snapshot-summaries&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#remote-instance-snapshot-summaries&quot;&gt;Remote Instance Snapshot Summaries&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of Snapshots: until this release, our automatic snapshot summary feature only worked with hosted instances. As of today, you can now get AI-generated summaries of snapshots of your remote instances as well.&lt;/p&gt;
&lt;p&gt;This is especially important for users with large remote instance deployments, and provides an important step forward in enabling FlowFuse users to manage and scale their deployments.&lt;/p&gt;
&lt;h2 id=&quot;saml-group-assertions-for-dashboard-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#saml-group-assertions-for-dashboard-development&quot;&gt;SAML Group Assertions for Dashboard Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing Dashboard permissions when building flows just got easier for Enterprise teams using SSO.&lt;/p&gt;
&lt;p&gt;We&#39;ve added an new option so that a users SSO Group memberships can be included in the &lt;code&gt;user&lt;/code&gt; object Dashboard flows receive when a user is logged in. This makes it much easier to build custom permissions into your FlowFuse Dashboard applications, giving you far more flexibility.&lt;/p&gt;
&lt;h2 id=&quot;device-agent-installer-handles-multiple-remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#device-agent-installer-handles-multiple-remote-instances&quot;&gt;Device Agent Installer handles Multiple Remote Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re continuing to work on making the process for installing the Device Agent as simple, easy, fast, and reliable as possible. With this release, the Device Agent Installer can install multiple Device Agents on a single remote device, by allowing you to install the Device Agent in a non-default directory and specify a non-default port. In addition, clearer installation summaries, documentation links, and improved installer output have improved the overall usability of the installer.&lt;/p&gt;
&lt;h2 id=&quot;dashboard-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#dashboard-fixes&quot;&gt;Dashboard Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, we&#39;ve made a number of small fixes that overall improve the Dashboard experience. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changeable colors on the X-axis&lt;/li&gt;
&lt;li&gt;Significantly decreased loading time for ui-chart&lt;/li&gt;
&lt;li&gt;Categorical line chart option&lt;/li&gt;
&lt;li&gt;Number inputs can be set to decimals&lt;/li&gt;
&lt;li&gt;Fixed some display bugs with the display when the sidebar is collapsed or uncollapsed&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;sneak-peek&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#sneak-peek&quot;&gt;Sneak Peek&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We&#39;re excited about a few more features that are just on the verge of being ready to ship! Here&#39;s a preview:&lt;/p&gt;
&lt;h2 id=&quot;detailed-access-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#detailed-access-control&quot;&gt;Detailed Access Control&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Until now, all user permissions in FlowFuse are set at the team level, where each user is either an Owner, Admin, Viewer, or Dashboard-only user, for everything in the team. If you wanted to set different permissions for different applications, you needed to put your application under a team where you had set the permissions you wanted: this made visibility difficult and increased the hassle of managing permissions.&lt;/p&gt;
&lt;p&gt;Now, permissions can be set at the application level. If you&#39;re a team running many different applications and need to organize who can access what, you are able to do that for each individual appication, significantly increasing the security and management abilities of FlowFuse.&lt;/p&gt;
&lt;p&gt;This feature will be available in the next few days - keep an eye on our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;ChangeLog&lt;/a&gt; for updates on when its available.&lt;/p&gt;
&lt;h2 id=&quot;ai-and-machine-vision&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#ai-and-machine-vision&quot;&gt;AI and Machine Vision&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Be on the lookout for some very cool applications of AI to machine vision!&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the next release, we&#39;ll provide support for building AI agents, real-time streaming protocol, a far more flexible Dashboard, bringing the FlowFuse Assistant to all self-hosted customers, and more! Stay tuned!&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.22 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.22.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/flowfuse-release-2-22/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/installing-node-red/</id>
        <title>Download Node-RED for Production: Windows, Mac, Linux, Raspberry Pi (2026)</title>
        <summary>Scale Node-RED from prototype to production with centralized management and 24/7 reliability</summary>
        <updated>2025-09-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/installing-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Installing Node-RED is straightforward. Install Node.js, run a command, and you&#39;re ready for visual programming in industrial automation. The real challenge begins when it must run across production lines, connect to PLCs, and stay operational 24/7.&lt;/p&gt;
&lt;h2 id=&quot;download-node-red-for-production-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#download-node-red-for-production-use&quot;&gt;Download Node-RED for Production Use&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Standalone Node-RED works great for testing, but production is different. When your flows control PLCs and critical equipment, downtime costs thousands per minute.&lt;/p&gt;
&lt;p&gt;Hardware fails. Networks drop. Power cuts out. Your Node-RED instance must restart automatically, handle connectivity issues, and keep production running without manual intervention. Deploying, managing and scaling must be easy and quick in such environments.&lt;/p&gt;
&lt;p&gt;Managing dozens of industrial PCs running Node-RED? You need centralized updates, secure remote access, proper backups, and role-based permissions. Your engineering team&#39;s months of flow development can&#39;t be lost to a hardware failure.&lt;/p&gt;
&lt;p&gt;Production Node-RED needs enterprise reliability, security, and management capabilities that the basic installation simply can&#39;t provide.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-for-production%3A-built-by-node-red%E2%80%99s-creator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#flowfuse-for-production%3A-built-by-node-red%E2%80%99s-creator&quot;&gt;FlowFuse for Production: Built by Node-RED’s Creator&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse was co-founded by &lt;a href=&quot;https://knolleary.net/about/&quot;&gt;Nick O&#39;Leary&lt;/a&gt;, the creator and project lead of Node-RED. Since creating Node-RED at IBM in 2013, Nick has led its evolution from an internal IoT tool into one of the most widely used low-code platforms for industrial automation, with millions of downloads each year. You can read the history of Node-RED written by Nick &lt;a href=&quot;https://flowfuse.com/blog/2024/02/history-of-nodered/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After more than a decade of working directly with enterprise users deploying Node-RED in production environments, Nick and the FlowFuse team built FlowFuse to address the operational challenges that standalone Node-RED cannot solve at scale.&lt;/p&gt;
&lt;p&gt;FlowFuse makes Node-RED production-ready through centralized management across industrial infrastructure, incorporating years of real-world deployment experience from the creator of Node-RED himself.&lt;/p&gt;
&lt;h3 id=&quot;enterprise-reliability-from-node-red-experts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#enterprise-reliability-from-node-red-experts&quot;&gt;Enterprise Reliability from Node-RED Experts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When hardware fails, FlowFuse keeps operations running through High Availability mode that distributes processing across multiple instances. Device Agents monitor system health and provide secure remote access for engineering teams—features designed by the same team that built and maintains Node-RED&#39;s core architecture.&lt;/p&gt;
&lt;p&gt;Engineering teams get proper DevOps workflows that move flows through development, testing, and production with automated deployments. Device grouping makes updates reach thousands of devices possible while version control and rapid rollbacks keep projects on track.&lt;/p&gt;
&lt;p&gt;Enterprise security comes built-in with single sign-on, role-based access control, comprehensive audit logging, and encrypted communications. Automated snapshots protect engineering work with rapid recovery when needed.&lt;/p&gt;
&lt;p&gt;These core capabilities are just the foundation—FlowFuse includes dozens of additional features designed specifically for industrial environments, refined through direct experience deploying Node-RED across Fortune 500 manufacturers and critical infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;trusted-by-industry-leaders&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#trusted-by-industry-leaders&quot;&gt;Trusted by Industry Leaders&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse is deployed in production environments across manufacturing, energy, and infrastructure sectors where Node-RED reliability is mission-critical. The platform&#39;s architecture reflects over 12 years of Node-RED development expertise and direct feedback from thousands of industrial deployments.&lt;/p&gt;
&lt;p&gt;As the official enterprise solution developed by Node-RED&#39;s creator, FlowFuse represents the authoritative approach to production Node-RED deployments, backed by the team with the deepest expertise in the technology.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#setting-up-flowfuse&quot;&gt;Setting Up FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sign up for the &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;14-day trial&lt;/a&gt; at FlowFuse, and you can get started immediately.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-add-remote-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#step-1%3A-add-remote-instance&quot;&gt;Step 1: Add Remote Instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the platform opens:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on &lt;strong&gt;Remote Instances&lt;/strong&gt; from the left sidebar&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Platform Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-remote-instance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse platform dashboard showing Remote Instances option&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add Remote Instance&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Add Remote Instance Button&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/platform-ff.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Button to add a new remote Node-RED instance&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Give it a name and select the device type&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Device Instance Configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/trail-add-instance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the remote device instance with name and type&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Select your application and click &lt;strong&gt;Add&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-2%3A-install-device-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#step-2%3A-install-device-agent&quot;&gt;Step 2: Install Device Agent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse shows you a device configuration window with two options. The &lt;strong&gt;One-Line Install&lt;/strong&gt; handles everything automatically. It installs Node.js if missing, installs the device agent, and registers your device with the platform.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;NPM Installation&lt;/strong&gt; method provides manual instructions for Windows, Mac, or Linux.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Device Configuration Window&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-configuration-window-2.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Device configuration window showing installation options for the FlowFuse Device Agent&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Follow the steps given within the window, which takes less than a minute to connect your device.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-manage-your-device&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#step-3%3A-manage-your-device&quot;&gt;Step 3: Manage Your Device&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once registered, you get complete control over your remote Node-RED instance through FlowFuse&#39;s management interface:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Device Management Tools&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-instance-tools.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Tools for managing Node-RED instance remotely via FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are even more features available at the application level and team level that you can explore. To remove infrastructure management complexity of required services such as MQTT and PostgreSQL, they are built-in and available for use.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-start-building&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#step-4%3A-start-building&quot;&gt;Step 4: Start Building&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To start building flows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable &lt;strong&gt;Developer Mode&lt;/strong&gt; from the top right&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Developer Mode Option&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/developer-mode.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Developer Mode Option&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Open Editor&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Developer Mode Option&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/open-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Open Editor Option&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Your automation flows now run with production reliability. Remote access works securely, and your team can collaborate while production continues running.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Developer Mode Option&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED Editor&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse bridges the gap between Node-RED&#39;s simplicity and production reliability requirements—built by the people who created Node-RED and understand its production needs better than anyone.&lt;/p&gt;
&lt;p&gt;Ready to see FlowFuse in action? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; and we&#39;ll show you how it works with your setup.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/</id>
        <title>Query Your Database with Natural Language Using FlowFuse Expert</title>
        <summary>A faster, more intuitive way to get data from your tables without writing a single line of SQL.</summary>
        <updated>2025-09-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Getting data from your database used to mean writing SQL queries. Not anymore. The FlowFuse Expert now lets you ask for what you want in plain English and automatically generates the SQL for you in query node.&lt;/p&gt;
&lt;h2 id=&quot;removing-technical-barriers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#removing-technical-barriers&quot;&gt;Removing Technical Barriers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial operations generate massive amounts of valuable data from sensors, equipment, and PLCs. This data can drive optimization and cost savings, but extracting insights often requires SQL skills that not every team member possesses.&lt;/p&gt;
&lt;p&gt;FlowFuse already makes it simple to connect to databases and build data flows using its Query nodes. However, the need to manually write SQL queries has remained a significant barrier for many users.&lt;/p&gt;
&lt;p&gt;To address this, FlowFuse continues its mission of making industrial automation accessible to everyone, regardless of coding expertise. Features like the FlowFuse Expert have already reduced complexity by enabling users to create custom functions and UI components using natural language.&lt;/p&gt;
&lt;p&gt;With FlowFuse &lt;a href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/&quot;&gt;2.21&lt;/a&gt;, this ease of use extends to database queries as well. Users can now ask questions in plain English and have SQL automatically generated, removing the last major hurdle and empowering a broader audience to gain actionable insights quickly and easily.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s see how this works with a practical example. This feature combines two FlowFuse components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Tables&lt;/strong&gt; provides the database connectivity and Query nodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Expert&lt;/strong&gt; adds the natural language processing capability that converts plain English into SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before you begin, make sure FlowFuse Tables is activated in your FlowFuse team. For more information, refer to &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/&quot;&gt;Getting Started with FlowFuse Tables&lt;/a&gt;. Then, import the following flow and deploy it to create a &lt;code&gt;sensor_readings&lt;/code&gt; table for practice:&lt;/p&gt;
&lt;div id=&quot;nr-flow-244&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow244 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;48b1380ff7bfe716&#92;&quot;,&#92;&quot;44bb8750d961e415&#92;&quot;,&#92;&quot;4a3976e062b2ddd2&#92;&quot;],&#92;&quot;x&#92;&quot;:274,&#92;&quot;y&#92;&quot;:419,&#92;&quot;w&#92;&quot;:572,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;48b1380ff7bfe716&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;44bb8750d961e415&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;44bb8750d961e415&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS public.sensor_readings ( (&#92;&#92;n    id SERIAL PRIMARY KEY,&#92;&#92;n    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),&#92;&#92;n    sensor_id VARCHAR(50) NOT NULL,&#92;&#92;n    location VARCHAR(100),&#92;&#92;n    temperature DECIMAL(5,2)&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4a3976e062b2ddd2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4a3976e062b2ddd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;4f24ab5b5628a1ba&#92;&quot;,&#92;&quot;fbf36a7b3c59461d&#92;&quot;],&#92;&quot;x&#92;&quot;:854,&#92;&quot;y&#92;&quot;:419,&#92;&quot;w&#92;&quot;:392,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;4f24ab5b5628a1ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scope&#92;&quot;:null,&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fbf36a7b3c59461d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fbf36a7b3c59461d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 6&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e465d4328d9d42d9&#92;&quot;,&#92;&quot;f8269cf412b4200f&#92;&quot;,&#92;&quot;2ce801643e01510b&#92;&quot;,&#92;&quot;40d48ffb90e5674a&#92;&quot;],&#92;&quot;x&#92;&quot;:274,&#92;&quot;y&#92;&quot;:519,&#92;&quot;w&#92;&quot;:972,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;e465d4328d9d42d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert simulated Data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;40d48ffb90e5674a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f8269cf412b4200f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ce801643e01510b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;INSERT INTO public.sensor_readings (sensor_id, timestamp, location, temperature) &#92;&#92;nVALUES ($sensor_id, $timestamp, $location, $temperature);&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:930,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f8269cf412b4200f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;40d48ffb90e5674a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d74afda3e83a644e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Generate last 7 days sensor data&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Generate simulated sensor readings for the last 7 days, at every even hour&#92;&#92;nlet now = new Date();&#92;&#92;nlet start = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); // 7 days ago&#92;&#92;nlet readings = [];&#92;&#92;n&#92;&#92;n// Collect all readings first&#92;&#92;nfor (let ts = new Date(start); ts &amp;lt;= now; ts.setHours(ts.getHours() + 1)) {&#92;&#92;n    if (ts.getHours() % 2 === 0) {&#92;&#92;n        readings.push({&#92;&#92;n            queryParameters: {&#92;&#92;n                sensor_id: &#92;&#92;&#92;&quot;sensor-1&#92;&#92;&#92;&quot;,&#92;&#92;n                timestamp: new Date(ts), // clone timestamp&#92;&#92;n                location: &#92;&#92;&#92;&quot;Lab A&#92;&#92;&#92;&quot;,&#92;&#92;n                temperature: Number((20 + Math.random() * 10).toFixed(2)) // Ensure number type&#92;&#92;n            }&#92;&#92;n        });&#92;&#92;n    }&#92;&#92;n}&#92;&#92;n&#92;&#92;n// Send them one by one with delay&#92;&#92;nreadings.forEach((reading, i) =&amp;gt; {&#92;&#92;n    setTimeout(() =&amp;gt; {&#92;&#92;n        node.send(reading);&#92;&#92;n    }, i * 200); // 200ms delay between messages&#92;&#92;n});&#92;&#92;n&#92;&#92;nreturn null; // Prevent immediate msg sending&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2ce801643e01510b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;89c52680263e6cba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/nr-tables-nodes&#92;&quot;:&#92;&quot;0.1.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow244.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-244&#39;) })&lt;/script&gt;
&lt;p&gt;After deployment, press the &amp;quot;Insert simulated Data&amp;quot; inject button to populate your table with a week&#39;s worth of hourly sensor readings. This sample data will help you explore Query node capabilities.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; FlowFuse Tables is currently available for Enterprise users only.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, let us test the natural language querying powered by the FlowFuse Expert:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add an Inject node to your flow&lt;/li&gt;
&lt;li&gt;Connect it to your Query node&lt;/li&gt;
&lt;li&gt;Open the Query node and locate the new &amp;quot;Assistant&amp;quot; codelens&lt;/li&gt;
&lt;li&gt;Enter: &amp;quot;Show me all readings from today&amp;quot;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Ask the FlowFuse Expert&lt;/strong&gt;. The FlowFuse Expert will process your natural language request and automatically generate the corresponding SQL query in the Query node&#39;s SQL field. Click Done.&lt;/li&gt;
&lt;li&gt;Connect a Debug node to see the results&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the Inject button to test it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert in Query Node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-ai-assistance-table-demo.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;FlowFuse Expert in Query Node&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;practical-query-examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#practical-query-examples&quot;&gt;Practical Query Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With your sample data in place, here are some immediately useful queries to try:&lt;/p&gt;
&lt;h3 id=&quot;performance-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#performance-analysis&quot;&gt;Performance Analysis&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Track temperature averages:&lt;/strong&gt;&lt;br /&gt;
Prompt: &amp;quot;What&#39;s the average temperature for this week?&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;MZxrI9SEegE&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identify peak readings:&lt;/strong&gt;&lt;br /&gt;
Prompt: &amp;quot;Find the highest temperature reading this month&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;jDIRH2i_1Uk&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;time-based-analysis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#time-based-analysis&quot;&gt;Time-Based Analysis&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Hourly patterns:&lt;/strong&gt;&lt;br /&gt;
Prompt: &amp;quot;Average temperature per hour today&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;m4L9ZHE6tdI&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;advanced-query-capabilities&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#advanced-query-capabilities&quot;&gt;Advanced Query Capabilities&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond basic queries, the FlowFuse Expert can handle sophisticated analysis:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Complex filtering:&lt;/strong&gt;&lt;br /&gt;
Prompt: &amp;quot;Show readings where temperature &amp;gt; 20, temperature &amp;lt; 25, and temperature ≠ 22&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;MtzcbmFg1-4&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Statistical operations:&lt;/strong&gt;&lt;br /&gt;
Prompt: &amp;quot;Calculate standard deviation of temperature readings this month&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;aJ8znXOn9Hc&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;These examples demonstrate how the FlowFuse Expert simplifies advanced analysis, turning complex database operations into easy, natural-language requests.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/ai-assistant-flowfuse-tables/#what&#39;s-next&quot;&gt;What&#39;s Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse Expert now brings natural language capabilities to database queries in FlowFuse Tables. This removes the complexity of SQL, allowing industrial teams to extract insights using simple conversational commands.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s mission has always been to democratize industrial automation and reduce complexity for engineers and operational teams. As part of this commitment, more AI-powered features are on the roadmap to simplify industrial workflows even further.&lt;/p&gt;
&lt;p&gt;Ready to transform how your team works with data? &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Book a demo&lt;/a&gt; and see how FlowFuse makes building industrial applications simple and accessible.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/</id>
        <title>Integrating LoRaWAN with FlowFuse</title>
        <summary>Connect and Communicate with LoRaWAN Devices using FlowFuse</summary>
        <updated>2025-09-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;LoRaWAN (Long Range Wide Area Network) is a low-power wireless protocol designed for IoT devices that need to transmit small amounts of data over long distances. FlowFuse is a platform that provides a visual programming interface for connecting IoT devices and services.&lt;/p&gt;
&lt;p&gt;By combining LoRaWAN with FlowFuse, you can easily collect data from remote sensors, process it, and integrate it with other systems or dashboards—all without writing complex code. In this article, we will guide you through setting up the integration and creating your first data processing flows.&lt;/p&gt;
&lt;h2 id=&quot;what-is-lorawan-and-how-does-it-work%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#what-is-lorawan-and-how-does-it-work%3F&quot;&gt;What is LoRaWAN and How Does It Work?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LoRaWAN is designed for devices that need to send small amounts of data over long distances while using very little battery power. Your sensors can communicate up to 15 kilometers away and run for years on a single battery.&lt;/p&gt;
&lt;p&gt;The system has three main parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;End devices - Your sensors that collect and send data&lt;/li&gt;
&lt;li&gt;Gateways - These receive data from your sensors and pass it along&lt;/li&gt;
&lt;li&gt;Network server - Manages everything and sends your data to applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thethingsnetwork.org/&quot;&gt;The Things Network (TTN)&lt;/a&gt; is a free, global LoRaWAN network with thousands of gateways around the world. It&#39;s perfect for getting started with LoRaWAN projects and provides easy-to-use tools for managing your devices.&lt;/p&gt;
&lt;p&gt;We&#39;ll show you how to connect TTN to FlowFuse for monitoring sensor data and building scalable industrial applications.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we understand the basics of LoRaWAN, let&#39;s set up the integration with FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we begin, make sure you have the following components ready:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Node-RED instance – Ensure you have a running Node-RED instance. The quickest way to set one up is through FlowFuse. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt;, create your instance, and you will be able to manage, deploy, scale, and secure your flows with ease. FlowFuse also provides enterprise-ready features out of the box.&lt;/li&gt;
&lt;li&gt;LoRaWAN device and gateway registered on TTN – You need a sensor or device connected to TTN and a gateway that can receive its uplinks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you do not have a LoRaWAN device, you can simulate one using available tools. For this article, I am using the &lt;a href=&quot;https://github.com/UniCT-ARSLab/LWN-Simulator&quot;&gt;LWN-Simulator&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-ttn-mqtt-connection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#setting-up-ttn-mqtt-connection&quot;&gt;Setting Up TTN MQTT Connection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TTN provides MQTT integration that allows external applications to receive uplink messages from your devices. We&#39;ll use this to connect TTN with FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;getting-ttn-connection-details&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#getting-ttn-connection-details&quot;&gt;Getting TTN Connection Details&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Log into your TTN Console (https://console.thethingsnetwork.org)&lt;/li&gt;
&lt;li&gt;Navigate to your application&lt;/li&gt;
&lt;li&gt;Go to the Other Integrations tab and select MQTT&lt;/li&gt;
&lt;li&gt;Note down the following connection details:
&lt;ul&gt;
&lt;li&gt;Server Address: Depends on your cluster, for example: &lt;code&gt;nam1.cloud.thethings.network&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Port: 1883 (for non-TLS) or 8883 (for TLS)&lt;/li&gt;
&lt;li&gt;Username: Your application ID&lt;/li&gt;
&lt;li&gt;Password: Your API key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of TTN console showing MQTT integration details including server address, port, username, and API key&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-connection-details.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of TTN console showing MQTT integration details including server address, port, username, and API key&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;configure-mqtt-node-and-receiving-uplink-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#configure-mqtt-node-and-receiving-uplink-messages&quot;&gt;Configure MQTT Node and Receiving Uplink Messages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Uplink messages are data transmissions sent from your LoRaWAN sensors and devices to Network and then forwarded to your applications. These messages contain sensor readings, status updates, or any other data your devices collect. Let&#39;s configure FlowFuse to receive these uplink messages.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your FlowFuse instance Editor.&lt;/li&gt;
&lt;li&gt;Drag an MQTT In node from the palette onto your workspace&lt;/li&gt;
&lt;li&gt;Double-click the node to configure it:
&lt;ul&gt;
&lt;li&gt;Server: Add a new MQTT broker configuration&lt;/li&gt;
&lt;li&gt;Host: Enter your TTN server address (e.g., nam1.cloud.thethings.network)&lt;/li&gt;
&lt;li&gt;Port: 1883 or 8883 (if using TLS)&lt;/li&gt;
&lt;li&gt;Username: Your TTN application ID&lt;/li&gt;
&lt;li&gt;Password: Your TTN API key&lt;/li&gt;
&lt;li&gt;Topic: &lt;code&gt;v3/{application-id}/devices/{device-id}/up&lt;/code&gt; (replace with your actual application and device IDs)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click Done to save the configuration&lt;/li&gt;
&lt;li&gt;Connect a Debug node to the output of your MQTT In node&lt;/li&gt;
&lt;li&gt;Deploy the flow by clicking the Deploy button&lt;/li&gt;
&lt;li&gt;Open the Debug panel to see incoming messages from your LoRaWAN device&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The messages you receive will be in JSON format and contain various fields as following:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;end_device_ids.device_id&lt;/td&gt;
&lt;td&gt;Unique identifier of the device in TTN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;end_device_ids.dev_eui&lt;/td&gt;
&lt;td&gt;Globally unique hardware identifier (EUI) of the device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;end_device_ids.join_eui&lt;/td&gt;
&lt;td&gt;Identifier used during device activation (JoinEUI/AppEUI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;end_device_ids.dev_addr&lt;/td&gt;
&lt;td&gt;Device address assigned by the network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;received_at&lt;/td&gt;
&lt;td&gt;Timestamp when TTN received the message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.f_port&lt;/td&gt;
&lt;td&gt;LoRaWAN port number (used to separate types of payloads)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.f_cnt&lt;/td&gt;
&lt;td&gt;Frame counter for tracking uplinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.frm_payload&lt;/td&gt;
&lt;td&gt;Raw payload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.decoded_payload&lt;/td&gt;
&lt;td&gt;Decoded values (requires a payload formatter in TTN)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.rx_metadata&lt;/td&gt;
&lt;td&gt;Metadata per gateway (includes RSSI, SNR, gateway ID, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.settings&lt;/td&gt;
&lt;td&gt;Radio parameters (frequency, data rate, spreading factor, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uplink_message.received_at&lt;/td&gt;
&lt;td&gt;Timestamp when TTN processed the uplink&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;correlation_ids&lt;/td&gt;
&lt;td&gt;IDs used internally to correlate events across the TTN stack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;processing-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#processing-data&quot;&gt;Processing Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s add some processing to extract and format the received data. This approach uses community-contributed nodes and requires minimal coding. Install the &lt;code&gt;node-red-node-base64&lt;/code&gt; and &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt; nodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a Change node and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.payload.uplink_message.frm_payload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Drag a base64 node and set the action to &amp;quot;Decode&amp;quot; (converts Base64 string to Buffer)&lt;/li&gt;
&lt;li&gt;Drag the buffer parser node and configure elements based on your data format&lt;/li&gt;
&lt;li&gt;Click the &amp;quot;+&amp;quot; button to add each element and fill in the following fields for each data point you want to extract:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Example Configuration for Temperature/Humidity Sensor:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Length&lt;/th&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Scale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;int16be&lt;/td&gt;
&lt;td&gt;temperature&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;int16be&lt;/td&gt;
&lt;td&gt;humidity&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Quick Parameter Guide:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type: How to read the bytes (int16be = 2-byte big-endian signed integer, uint8 = 1-byte unsigned integer)&lt;/li&gt;
&lt;li&gt;Name: What to call it in your output (becomes msg.payload.temperature)&lt;/li&gt;
&lt;li&gt;Length: Number of bytes to read (2 for int16be, 1 for uint8)&lt;/li&gt;
&lt;li&gt;Offset: Where to start reading (0 = first byte, 2 = third byte, etc.)&lt;/li&gt;
&lt;li&gt;Scale: Math to apply (0.01 = divide by 100, 1 = no scaling)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Connect the MQTT in node to the input of change node, change node output to base64 node and base64 node output to the input of buffer parser and add the debug node at the end to see the output.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you will see the object with the parsed sensor data in the debug panel. The output will show something like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-459&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-459&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;21.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;humidity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;57.2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-459&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;As you can see in the image below, TTN console shows live data with uplink message on the left side, and FlowFuse successfully reads and processes it on the right side.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing TTN console with live uplink messages on the left and FlowFuse debug panel with processed sensor data on the right&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/live-data-ttn-ff1.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing TTN console with live uplink messages on the left and FlowFuse debug panel with processed sensor data on the right&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;sending-commands-to-devices-(downlink)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#sending-commands-to-devices-(downlink)&quot;&gt;Sending Commands to Devices (Downlink)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Downlink messages are commands sent from your application back to LoRaWAN devices through the network. These messages allow you to remotely control your devices, update their configuration, trigger specific actions, or send firmware updates. LoRaWAN devices can only receive downlink messages during their receive windows after sending an uplink, making this communication asynchronous but highly power-efficient.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag a Function node and add JavaScript to format the downlink message with the data you want to send. Alternatively, you can use a Change node with a Base64 node for a low-code approach.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-484&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-484&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Example: Send a command to turn on LED or change sensor interval&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; downlinkMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;downlinks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;f_port&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Port number (1-223)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;frm_payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x01&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x0A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;base64&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Command bytes&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NORMAL&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;downlinkMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-484&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Downlink Properties Explanation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;f_port&lt;/code&gt;: The LoRaWAN port number (1-223) used to differentiate message types&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frm_payload&lt;/code&gt;: Your command data encoded as Base64 string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt;: Message priority (&amp;quot;LOWEST&amp;quot;, &amp;quot;LOW&amp;quot;, &amp;quot;BELOW_NORMAL&amp;quot;, &amp;quot;NORMAL&amp;quot;, &amp;quot;ABOVE_NORMAL&amp;quot;, &amp;quot;HIGH&amp;quot;, &amp;quot;HIGHEST&amp;quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Add an MQTT Out node to your workspace&lt;/li&gt;
&lt;li&gt;Configure it with the same TTN broker settings as your MQTT In node&lt;/li&gt;
&lt;li&gt;Set the topic to: &lt;code&gt;v3/{application-id}/devices/{device-id}/down/push&lt;/code&gt; (replace with your actual application and device IDs)&lt;/li&gt;
&lt;li&gt;Connect the Inject node to Function node and Function node to MQTT out node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the image below, you can see FlowFuse sending and processing the downlink message, while TTN console displays the live data on the left.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing TTN console with live Downlink messages on the left and FlowFuse debug panel with processed sensor data on the right&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/live-data-ttn-downlink.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing TTN console with live Downlink messages on the left and FlowFuse debug panel with processed sensor data on the right&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/integrating-lorawan-with-flowfuse-node-red/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next, you can store this data in a database. With FlowFuse, a managed PostgreSQL database is already provided—so you do not need to install or configure one manually. FlowFuse also offers a Query node that is automatically configured for your instance. Inside the Query node, you can use FlowFuse Expert, which allows you to write natural language prompts instead of SQL queries. The assistant will generate SQL automatically based on your table schema.&lt;/p&gt;
&lt;p&gt;For a complete guide on storing and visualizing data, see the article on &lt;a href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/&quot;&gt;Building Historical Data Dashboards with FlowFuse Tables&lt;/a&gt;. It also includes step-by-step instructions for creating dashboards using &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt;—a low-code way to build powerful industrial dashboards that also allows you to send downlink data to devices interactively.&lt;/p&gt;
&lt;p&gt;With FlowFuse, you get a complete enterprise-grade platform built around visual programming—perfect for production-ready IoT deployments. It adds powerful capabilities like centralized management of Node-RED instances, DevOps tools, snapshots, real-time team collaboration, audit logs, RBAC, SSO, Built mqtt broker and database service and more—all designed to help you scale and manage your applications with ease.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in exploring FlowFuse further for your industrial IoT applications, come visit us at our booth at upcoming TTN conferences to see live manufacturing demos. You can also &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt; to see how FlowFuse can streamline your development and deployment workflows, or &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;start your free trial&lt;/a&gt; and build your first LoRaWAN-enabled dashboard today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/</id>
        <title>Poka Yoke (Poke Yoke, Bokayoke) Explained: Definition, Examples, Types (2026)</title>
        <summary>How to mistake-proof your manufacturing processes</summary>
        <updated>2025-09-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Every day, skilled operators make mistakes that cost thousands. A component installed backwards. A critical step skipped during rush orders. A measurement misread at shift&#39;s end.&lt;/p&gt;
&lt;p&gt;The shocking truth? Human errors account for nearly 23% of manufacturing defects worldwide, costing businesses billions annually. But here&#39;s what&#39;s different: companies implementing poka yoke have reduced defects by up to 50% and increased production efficiency by 30%.&lt;/p&gt;
&lt;p&gt;What if the problem isn&#39;t your people—but your processes?&lt;/p&gt;
&lt;h2 id=&quot;what-does-poka-yoke-(often-misspelled-as-bokayoke-or-poke-yoke)-mean-and-where-did-it-come-from%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#what-does-poka-yoke-(often-misspelled-as-bokayoke-or-poke-yoke)-mean-and-where-did-it-come-from%3F&quot;&gt;What Does Poka Yoke (Often Misspelled as Bokayoke or Poke Yoke) Mean and Where Did It Come From?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Poka yoke (pronounced &amp;quot;POH-kah YOH-kay&amp;quot;) is a Japanese term that means &amp;quot;mistake-proofing&amp;quot; or &amp;quot;error prevention.&amp;quot; The phrase comes from &lt;strong&gt;&amp;quot;poka o yokeru&amp;quot; (ポカを避ける)&lt;/strong&gt;—literally, avoiding an unthinkably bad move in the game of shogi. While it&#39;s sometimes misspelled as bokayoke or poke yoke, and formally written as poka-yoke with a hyphen, the correct term is &lt;strong&gt;poka yoke&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In 1961, a Japanese electronics plant faced a staggering 25% defect rate. Workers kept missing tiny springs in switch assemblies—not due to carelessness, but because the repetitive handling of microscopic components made mistakes inevitable.&lt;/p&gt;
&lt;p&gt;Toyota engineer &lt;a href=&quot;https://en.wikipedia.org/wiki/Shigeo_Shingo&quot;&gt;Shigeo Shingo&lt;/a&gt; introduced a simple but revolutionary solution: a fixture holding exactly two springs for each assembly. Workers had to remove both springs before starting their task, instantly highlighting any incomplete assembly. As a result, defects dropped to zero overnight—without additional training.&lt;/p&gt;
&lt;p&gt;Originally called &lt;strong&gt;&amp;quot;baka-yoke&amp;quot; (idiot-proofing)&lt;/strong&gt;, the technique was renamed &lt;strong&gt;poka yoke&lt;/strong&gt; after a worker objected, emphasizing that human errors are natural, not a reflection of intelligence.&lt;/p&gt;
&lt;p&gt;Shingo made a key distinction between human mistakes and production defects. Mistakes happen—they&#39;re part of being human. Defects occur when those mistakes reach the customer. Poka yoke focuses on designing processes so mistakes are immediately detected and corrected, eliminating defects at the source. This philosophy shifts manufacturing focus: rather than trying to perfect human behavior, perfect the systems in which humans work.&lt;/p&gt;
&lt;h2 id=&quot;poka-yoke-definition%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#poka-yoke-definition%3F&quot;&gt;Poka Yoke Definition?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Poka yoke is a systematic approach that uses automatic devices or methods to either make errors impossible or make them immediately obvious once they occur. It&#39;s any mechanism that helps equipment operators avoid mistakes by preventing, correcting, or drawing attention to human errors as they happen.&lt;/p&gt;
&lt;p&gt;The poka yoke meaning extends beyond simple error prevention. Rather than treating errors as moral failures or training deficiencies, it treats them as design problems. This lean manufacturing approach recognizes that even the most skilled workers experience moments of distraction, fatigue, or cognitive overload.&lt;/p&gt;
&lt;p&gt;Traditional quality control detects defects after they occur, requiring inspection, rework, and often scrapping of materials. The poka yoke approach prevents defects during production by making errors physically impossible or immediately visible. This prevention-first approach creates a cascading effect: quality control teams focus on complex issues rather than basic errors, workers gain confidence in their processes, customer satisfaction improves through consistent product quality, and excellence becomes the natural outcome rather than a heroic achievement.&lt;/p&gt;
&lt;p&gt;If you prefer a video format, watch this short and clear video explaining what poka yoke is:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;JTI_-xwIIg8&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-is-poka-yoke-important-for-manufacturers%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#why-is-poka-yoke-important-for-manufacturers%3F&quot;&gt;Why Is Poka Yoke Important for Manufacturers?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The impact of mistake-proofing extends far beyond just catching errors. By designing assembly processes that are mistake-proof, poka yoke prevents defects from occurring in the first place rather than inspecting quality issues later. Companies achieve defect rates measured in parts per million rather than percentages.&lt;/p&gt;
&lt;p&gt;Errors in manual assembly lead to increased scrap rates, rework, and delays—all contributing to higher production costs. By eliminating errors at the source, the cost of mistakes within a company is reduced significantly. Companies implementing poka yoke techniques saw a 25% increase in productivity, with time previously spent correcting errors now available for value-added activities.&lt;/p&gt;
&lt;p&gt;Mistake-proofing creates safer processes by eliminating conditions that lead to accidents. When errors can literally mean life or death (as in pharmaceutical manufacturing), poka yoke becomes mission-critical. Workers experience less frustration from rework and greater confidence in their processes, leading to improved morale. Successful implementation leads to a 20% improvement in customer satisfaction through consistent product quality and reliability.&lt;/p&gt;
&lt;p&gt;The benefits of poka yoke in manufacturing deliver measurable business outcomes: defect elimination achieving near-zero defects, waste reduction across the eight forms identified in lean manufacturing, process simplification turning complex procedures into straightforward steps, real-time correction catching mistakes immediately rather than weeks later, scalable quality built into the system rather than dependent on individual heroics, and continuous improvement creating a foundation for ongoing kaizen activities.&lt;/p&gt;
&lt;h2 id=&quot;poka-yoke-types%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#poka-yoke-types%3F&quot;&gt;Poka Yoke Types?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding the types of poka yoke helps you choose the right approach for your specific error prevention needs.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;contact method&lt;/strong&gt; identifies product defects by testing the product&#39;s shape, size, color, or other physical attributes. This uses physical design features to make mistakes impossible. Diesel fuel nozzles are sized larger than gasoline tank openings—you literally can&#39;t put diesel in a gas car. USB-C connectors only fit one way, preventing incorrect insertion. Parts with unique shapes only fit correctly in assembly fixtures, and machine guards prevent equipment operation until properly closed. This is the most effective mistake-proofing method because it makes errors physically impossible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixed-value methods&lt;/strong&gt; often involve measurement devices such as scales or counters to prevent or identify nonconformances. These build the right limits directly into your tools. Torque wrenches automatically stop at correct force. Parts trays hold exactly the number of components needed—leftovers indicate a missing part. Automated pill dispensers count exact doses, weight verification systems ensure complete assemblies, and digital counters track the number of operations performed. If there are leftover parts or incorrect counts, something&#39;s wrong—and you know immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motion-step methods&lt;/strong&gt; focus on ensuring operators perform the right steps in the correct sequence. These force the correct sequence of operations. Lockout/tagout systems prevent equipment access until safety steps are complete. CNC machines require tool verification before program execution. Assembly stations physically prevent advancement until the current step is finished, sequential interlocks ensure proper startup and shutdown procedures, and guided work instructions must be completed in order. These turn complex procedures into foolproof, step-by-step processes.&lt;/p&gt;
&lt;p&gt;Beyond these three detection methods, poka yoke systems function in two fundamental ways: control-based and warning-based. Control poka yoke actually prevents the mistake from being made, making it mechanically or electronically impossible for errors to occur. Think of a car transmission requiring &amp;quot;Park&amp;quot; or &amp;quot;Neutral&amp;quot; to start, or computer forms that won&#39;t submit until all required fields are filled. Use this when errors must be prevented entirely, especially for safety-critical operations. Warning-based poka yoke alerts operators to occurring or soon-to-occur defects, relying on human intervention to stop and correct errors. Examples include backup sensors beeping when you&#39;re too close to an obstacle, warning lights indicating missing components, or Outlook reminding you about missing attachments. The key difference: control systems stop the process automatically; warning systems rely on human response.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-6-steps-of-poka-yoke-mistake-proofing%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#what-are-the-6-steps-of-poka-yoke-mistake-proofing%3F&quot;&gt;What Are the 6 Steps of Poka Yoke Mistake-Proofing?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Implementing poka yoke follows a systematic six-step process that ensures effective error prevention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Identify the Problem.&lt;/strong&gt; Create a detailed process flowchart mapping every operation, no matter how small. Review each step to determine where human errors are likely to occur, which can involve using the 5 Whys technique. Where do defects occur most frequently? Which errors have the highest impact? What causes operators the most difficulty? Use tools like Pareto analysis to prioritize—typically 80% of defects come from 20% of causes. Before implementing any mistake-proofing tools or poka yoke devices, you need to identify your most frequent quality problems. A Pareto chart analysis helps you prioritize which defects cause 80% of your quality issues, ensuring you focus your poka yoke efforts where they&#39;ll have maximum impact. &lt;a href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/&quot;&gt;Learn how to create effective Pareto charts for quality analysis&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Analyze Root Causes.&lt;/strong&gt; Once every potential error is found, work through the process to find the root cause. Don&#39;t just identify when errors occur—understand why they happen. Use techniques like 5 Whys analysis, fishbone diagrams, process mapping, Failure Mode and Effects Analysis (FMEA), and gemba walks (go see where work happens). Understanding root causes prevents implementing complex solutions for simple problems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Design the Solution.&lt;/strong&gt; Design solutions in the process to eliminate the risk of the error ever happening, which can include eliminating the step or replacing it with a mistake-proof step. The solution hierarchy from most to least effective includes elimination (remove the error-prone step entirely), replacement (substitute with an error-proof alternative), facilitation (make correct actions significantly easier than errors), detection (identify errors immediately when they occur), and mitigation (minimize effects if errors reach this point). The four key principles are elimination, prevention, detection, and mitigation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Choose the Implementation Method.&lt;/strong&gt; Select the appropriate mistake-proofing technique based on your specific situation. Consider inspection methods like source inspection (checks before the process step occurs), self-inspection (workers check their own work immediately), or successive inspection (next worker verifies previous step). Choose setting functions such as contact/physical checks, fixed-value counting or weighing, motion-step sequence verification, or information enhancement for visibility. Decide on regulatory functions including warning signals (lights, buzzers, colors) or control mechanisms (preventing advancement).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Test the Poka Yoke.&lt;/strong&gt; A poka yoke pilot project will help you iron out any issues with the process before introducing it to your shop floor. Does it prevent or detect the target error? Does it slow down production unacceptably? Can it create new safety hazards? Does it introduce new failure modes? Do operators understand and accept it? Is it cost-effective? Start small, validate effectiveness, then scale up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6: Implement and Monitor.&lt;/strong&gt; Roll out the solution with proper training and documentation. But implementation isn&#39;t the end—it&#39;s the beginning of continuous improvement. Monitor error rates before and after implementation, track effectiveness metrics, gather operator feedback, make adjustments as needed, apply successful solutions to similar processes, and update FMEA documentation. Remember: poka yoke is about continuous improvement, not one-time fixes.&lt;/p&gt;
&lt;h2 id=&quot;poka-yoke-examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#poka-yoke-examples&quot;&gt;Poka Yoke Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The automobile industry showcases poka yoke transformative applications across assembly lines and production processes. Toyota&#39;s implementation includes fixtures that physically prevent incorrect part installation and sensors that detect missing components before products advance to subsequent stations. These systems have helped achieve defect rates measured in parts per million rather than percentages, setting industry standards for quality excellence.&lt;/p&gt;
&lt;p&gt;Electronics manufacturing demonstrates sophisticated applications in high-precision environments. Component placement machines verify correct parts before PCB assembly, preventing costly defects that would be difficult or impossible to correct later. Color-coded component storage and automated inventory systems ensure operators select correct parts while maintaining production speed and efficiency.&lt;/p&gt;
&lt;p&gt;Pharmaceutical production represents perhaps the most critical mistake-proofing applications, where errors can literally mean life or death. Automated dosing systems prevent medication errors, while segregated production lines eliminate cross-contamination risks. Barcode scanning and weight verification create multiple checkpoints that ensure accurate formulations without slowing production processes.&lt;/p&gt;
&lt;p&gt;You encounter mistake-proofing daily in everyday life, often without noticing. In your car, manual transmissions require clutch depression to start, automatic transmissions require &amp;quot;Park&amp;quot; or &amp;quot;Neutral&amp;quot; to start, seat belt warnings sound until buckled, and keys must be in the ignition to remove from &amp;quot;Park.&amp;quot; Technology examples include USB connectors that only fit one orientation, spell-check catching errors as you type, email reminders about missing attachments, forms preventing submission until all fields are complete, and phone warnings before deleting photos. Around your home and office, overflow drains prevent bathtub floods, three-prong plugs ensure proper grounding, microwave doors stop operation when opened, hotel room keycards control energy consumption, and pen clips retract tips to prevent pocket damage.&lt;/p&gt;
&lt;h2 id=&quot;is-poka-yoke-right-for-you%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#is-poka-yoke-right-for-you%3F&quot;&gt;Is Poka Yoke Right for You?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Poka yoke is particularly valuable when you&#39;re experiencing repetitive defects that training alone can&#39;t fix, high-volume production where small error rates create massive waste, safety-critical operations where mistakes could cause injury, complex assemblies with multiple potential error points, or processes where inspection after production is too late or too expensive.&lt;/p&gt;
&lt;p&gt;However, poka yoke isn&#39;t always the answer. For truly unique, one-off custom work, the investment in mistake-proofing devices may not be justified. When processes change frequently, rigid mistake-proofing systems can become obstacles. In highly creative work where &amp;quot;mistakes&amp;quot; sometimes lead to innovation, too much control can stifle breakthroughs.&lt;/p&gt;
&lt;p&gt;The key question: Are errors systematic or random? If the same mistakes happen repeatedly, poka yoke is your solution. If every error is unique and unpredictable, focus on training and skill development instead.&lt;/p&gt;
&lt;h2 id=&quot;how-to-implement-poka-yoke-in-your-manufacturing-processes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#how-to-implement-poka-yoke-in-your-manufacturing-processes&quot;&gt;How to Implement Poka Yoke in Your Manufacturing Processes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Successful poka yoke implementation begins with systematic error pattern analysis through root cause investigation and detailed process mapping. Understanding why errors occur—rather than just when they occur—enables targeted mistake-proofing techniques that address underlying causes rather than symptoms. This analytical foundation prevents the common mistake of implementing complex solutions for simple problems.&lt;/p&gt;
&lt;p&gt;Employee involvement throughout the design process proves crucial for successful adoption. Operators who participate in solution development understand the reasoning behind changes and can provide valuable insights about practical implementation challenges. Their buy-in transforms potential resistance into enthusiastic support for quality improvement initiatives aligned with poka yoke principles.&lt;/p&gt;
&lt;p&gt;Testing and refinement cycles validate system effectiveness before full-scale deployment. Pilot implementations reveal unexpected challenges and opportunities for improvement while building confidence in proposed solutions. This iterative approach prevents costly mistakes and ensures solutions work effectively in real production environments.&lt;/p&gt;
&lt;p&gt;Start simple by focusing on obvious, high-impact problems using basic mistake-proofing examples before tackling complex issues. Prioritize cost-effective solutions and devices that deliver measurable results. Include operators in design for better adoption rates, following kanban poka yoke and kaizen principles. Build mistake-proofing into standard operating procedures and integrate it with Six Sigma methodologies. Conduct regular reviews and enhancements of existing systems for continuous improvement.&lt;/p&gt;
&lt;h2 id=&quot;modern-digital-poka-yoke%3A-engineering-mistake-proof-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#modern-digital-poka-yoke%3A-engineering-mistake-proof-systems&quot;&gt;Modern Digital Poka Yoke: Engineering Mistake-Proof Systems&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The future of poka yoke increasingly incorporates Industry 4.0 technologies that expand traditional concepts. IoT sensors provide real-time capabilities that detect deviations instantly, while machine learning algorithms identify subtle patterns that predict potential failures before they occur. These advanced digital tools complement rather than replace fundamental poka yoke principles.&lt;/p&gt;
&lt;p&gt;Modern smart manufacturing systems integrate digital work instructions that guide operators through complex procedures step-by-step, ensuring consistency while accommodating process variations. Adaptive tooling automatically adjusts parameters based on real-time measurements, preventing specification deviations while maintaining production efficiency.&lt;/p&gt;
&lt;p&gt;FlowFuse enables sophisticated poka yoke implementations by connecting IoT sensors, machine data, and quality control systems in real-time workflows. Manufacturing teams can build automated solutions that trigger immediate alerts, stop processes when deviations occur, and guide operators through corrective actions—all without complex programming or expensive custom solutions. To learn more or see it in action, you can &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;get in touch&lt;/a&gt; with the team.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The poka yoke technique represents more than a quality improvement method—it embodies a fundamental shift toward designing human error out of manufacturing processes. By accepting human fallibility and engineering around it, manufacturers achieve consistent quality while reducing costs and improving employee satisfaction.&lt;/p&gt;
&lt;p&gt;The method&#39;s enduring relevance in an era of smart manufacturing demonstrates that the most powerful solutions often combine simple principles with sophisticated execution. Whether you&#39;re implementing basic mistake-proofing devices or advanced IoT-enabled systems, the core philosophy remains unchanged: make errors impossible, or make them immediately obvious.&lt;/p&gt;
&lt;p&gt;The question isn&#39;t whether poka yoke works—decades of success across industries prove it does. The question is: which errors in your process are you ready to eliminate forever?&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/poka-yoke-mistake-proofing/#references&quot;&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Shingo, Shigeo. &amp;quot;Zero Quality Control: Source Inspection and the Poka-Yoke System.&amp;quot; Productivity Press, 1986.&lt;/li&gt;
&lt;li&gt;Liker, Jeffrey K. &amp;quot;The Toyota Way: 14 Management Principles from the World&#39;s Greatest Manufacturer.&amp;quot; McGraw-Hill Education, 2004.&lt;/li&gt;
&lt;li&gt;Robinson, Harry. &amp;quot;Using Poka Yoke Techniques for Early Defect Detection.&amp;quot; International Conference on Software Testing, 1999.&lt;/li&gt;
&lt;li&gt;Womack, James P., Jones, Daniel T. &amp;quot;Lean Thinking: Banish Waste and Create Wealth in Your Corporation.&amp;quot; Free Press, 2003.&lt;/li&gt;
&lt;li&gt;ASQ Quality Press. &amp;quot;The Certified Quality Engineer Handbook, Fourth Edition.&amp;quot; American Society for Quality, 2013.&lt;/li&gt;
&lt;li&gt;Toyota Motor Corporation. &amp;quot;Toyota Production System: Beyond Large-Scale Production.&amp;quot; Productivity Press, 1988.&lt;/li&gt;
&lt;li&gt;Pyzdek, Thomas, Keller, Paul. &amp;quot;The Six Sigma Handbook: A Complete Guide for Green Belts, Black Belts, and Managers.&amp;quot; McGraw-Hill Education, 2014.&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/what-is-5s-checklist/</id>
        <title>What is 5S Checklist: Definition, Benefits, Implementation, and Template</title>
        <summary>Understand 5S Checklists, Improve Work Area Efficiency, and Start with a Ready-to-Use FlowFuse Template</summary>
        <updated>2025-09-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/what-is-5s-checklist/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Manufacturing environments face increasing pressure to eliminate waste, improve safety, and maintain quality standards. Disorganized workspaces contribute to production delays, safety incidents, and quality defects that directly impact operational performance. The 5S methodology addresses these challenges through systematic work area organization, but implementation requires consistent evaluation and measurement. A 5S checklist provides the structured framework necessary to assess, maintain, and improve work area organization standards across manufacturing operations.&lt;/p&gt;
&lt;h2 id=&quot;understanding-5s-methodology&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#understanding-5s-methodology&quot;&gt;Understanding 5S Methodology&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The 5S methodology originated in Japanese manufacturing and has become the gold standard for work area organization worldwide. The name comes from five Japanese words that each begin with &#39;S&#39;, representing a systematic approach to creating efficient, safe workspaces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sort (Seiri)&lt;/strong&gt; means removing everything that doesn&#39;t belong in your workspace. This involves ruthlessly eliminating &amp;quot;just in case&amp;quot; items that create clutter and reduce efficiency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set in Order (Seiton)&lt;/strong&gt; gives everything that remains a logical, designated home based on frequency of use and workflow patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shine (Seiso)&lt;/strong&gt; focuses on cleanliness that reveals problems early. Oil leaks, wear patterns, and safety hazards become immediately visible in clean environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standardize (Seiketsu)&lt;/strong&gt; creates consistent procedures so everyone follows identical organizational principles across shifts and departments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sustain (Shitsuke)&lt;/strong&gt; builds the culture and accountability systems needed to maintain improvements permanently.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The challenge isn’t just understanding these concepts; it’s implementing them consistently across different operations.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-a-5s-checklist-essential&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#what-makes-a-5s-checklist-essential&quot;&gt;What Makes a 5S Checklist Essential&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A 5S checklist transforms abstract organizational principles into concrete, measurable actions with specific evaluation criteria. Instead of subjective opinions about workspace organization, teams get objective standards: Is every tool in its designated shadow board outline? Are walkways completely obstacle-free? Can someone new find required materials within two minutes?&lt;/p&gt;
&lt;p&gt;Beyond simple evaluation, these checklists serve as training tools for new employees, communication devices between shifts, historical records showing improvement trends, and accountability systems that prevent 5S from becoming another forgotten initiative.&lt;/p&gt;
&lt;h2 id=&quot;essential-5s-checklist-items-every-work-area-needs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#essential-5s-checklist-items-every-work-area-needs&quot;&gt;Essential 5S Checklist Items Every work area Needs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While each work environment requires specific evaluation criteria, certain fundamental items should be included in every 5S checklist. Here is a practical framework of 25 questions that you can adapt for your operations.&lt;/p&gt;
&lt;h3 id=&quot;sort&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#sort&quot;&gt;Sort&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Are workstations free of unnecessary materials, tools, and equipment?&lt;/li&gt;
&lt;li&gt;Have outdated documents and reference materials been removed?&lt;/li&gt;
&lt;li&gt;Are broken or obsolete items properly tagged for disposal?&lt;/li&gt;
&lt;li&gt;Do storage areas contain only frequently used items?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;set-in-order&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#set-in-order&quot;&gt;Set in Order&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Is every tool in its designated location with clear identification?&lt;/li&gt;
&lt;li&gt;Are frequently used items positioned within easy reach?&lt;/li&gt;
&lt;li&gt;Are visual management systems (labels, shadow boards, floor markings) clearly visible?&lt;/li&gt;
&lt;li&gt;Can workers retrieve needed items without searching or moving obstacles?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;shine&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#shine&quot;&gt;Shine&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Are all surfaces, equipment, and floors properly cleaned?&lt;/li&gt;
&lt;li&gt;Are maintenance schedules current and inspection logs up-to-date?&lt;/li&gt;
&lt;li&gt;Are cleaning supplies readily available and properly stored?&lt;/li&gt;
&lt;li&gt;Are leaks, spills, and abnormal conditions immediately visible?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;standardize&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#standardize&quot;&gt;Standardize&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Are work instructions current, accessible, and consistently followed?&lt;/li&gt;
&lt;li&gt;Do similar workstations follow identical organizational principles?&lt;/li&gt;
&lt;li&gt;Are all team members trained on current 5S standards?&lt;/li&gt;
&lt;li&gt;Are procedures regularly reviewed and updated?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sustain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#sustain&quot;&gt;Sustain&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Do workers maintain organizational standards without constant supervision?&lt;/li&gt;
&lt;li&gt;Are team members actively identifying improvement opportunities?&lt;/li&gt;
&lt;li&gt;Do supervisors regularly participate in evaluations and improvements?&lt;/li&gt;
&lt;li&gt;Are 5S achievements recognized and celebrated?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-real-impact-on-your-operations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#the-real-impact-on-your-operations&quot;&gt;The Real Impact on Your Operations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Companies that implement 5S checklists consistently report dramatic improvements that go far beyond having a tidy workspace. Workers typically spend less time searching for tools and materials once proper organization takes hold. This isn&#39;t just about efficiency, it&#39;s about frustration levels and job satisfaction too.&lt;/p&gt;
&lt;p&gt;Safety improvements often exceed expectations. When everything has a proper place and workspaces stay clean, accident rates can drop. Spills get noticed and cleaned immediately instead of becoming slip hazards. Tools don&#39;t get left in walkways where someone might trip.&lt;/p&gt;
&lt;p&gt;Quality improvements follow naturally from better organization. Clean, well-organized environments make it easier to spot problems before they become defects. When workers aren&#39;t rushed or frustrated from searching for materials, they make fewer mistakes. The predictability of well-organized processes reduces variability in outcomes.&lt;/p&gt;
&lt;p&gt;Perhaps surprisingly, employee engagement often increases significantly. Teams take pride in maintaining organized workspaces, especially when they participate in regular evaluations and see their scores improve over time. The checklist process gives everyone a voice in work area improvement.&lt;/p&gt;
&lt;h2 id=&quot;making-implementation-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#making-implementation-work&quot;&gt;Making Implementation Work&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Starting a successful 5S checklist program requires more than distributing forms. Begin with leadership commitment and comprehensive training so everyone understands both the evaluation process and its connection to their daily work experience.&lt;/p&gt;
&lt;p&gt;Create area-specific checklists rather than generic ones. A machine shop needs different evaluation criteria than an assembly line or office environment. While core 5S principles remain constant, specific items should reflect each workspace&#39;s unique requirements.&lt;/p&gt;
&lt;p&gt;Establish regular evaluation cycles: daily quick checks for immediate problems, weekly detailed reviews for improvement planning, and monthly comprehensive evaluations for trend analysis. The crucial element many programs miss is systematic follow-through. Identifying problems only creates value when those problems get solved with assigned responsibility and completion tracking.&lt;/p&gt;
&lt;h2 id=&quot;the-digital-advantage-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#the-digital-advantage-with-flowfuse&quot;&gt;The Digital Advantage with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Traditional paper checklists have inherent limitations. Results get lost, data analysis becomes time-consuming, and accessing information from multiple locations proves challenging. Digital solutions eliminate these problems while adding capabilities that paper cannot match.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s low-code Node-RED interface makes building sophisticated 5S checklist applications accessible without extensive programming backgrounds. You can create custom evaluation forms capturing exactly the information your operation needs. Simple yes/no questions, numerical scores, or detailed condition comments.&lt;/p&gt;
&lt;p&gt;As an industrial data platform, FlowFuse enables seamless integration of 5S checklists into broader operational workflows, connecting work area organization efforts with real-time factory data for comprehensive improvement insights.&lt;/p&gt;
&lt;p&gt;Mobile access transforms team interaction with the evaluation process. Workers complete checklists on tablets or smartphones directly in work areas, take photos documenting conditions, and immediately see how current scores compare to previous evaluations. This real-time feedback creates engagement impossible with paper forms.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; for FlowFuse now and get started building your individual 5S checklist.&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/what-is-5s-checklist/#up-next&quot;&gt;Up next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to start immediately without creating a checklist from scratch, FlowFuse’s pre-built 5S Checklist Blueprint is ready to use. It includes 25 evaluation questions to assess work area organization, scoring to measure compliance, and follow-up tracking to ensure issues are resolved. The dashboard provides a clear view of improvements over time, and the entire system is fully customizable to match the unique needs of your operations.&lt;/p&gt;
&lt;div class=&quot;cta-card&quot; style=&quot;display: flex; align-items: center; gap: 20px; background-color: #EEF2FF; padding: 20px; border-radius: 8px; font-family: sans-serif; border: 1px solid #6366F1;&quot;&gt;  
    &lt;!-- Left side image --&gt;  
    &lt;div style=&quot;flex: 1;&quot;&gt;  
        &lt;img src=&quot;https://flowfuse.com/img/5s-checklist-eYy2xo4REM-650.avif&quot; alt=&quot;FlowFuse 5S Checklist Blueprint&quot; style=&quot;width: 100%; height: auto; border-radius: 6px;&quot; /&gt;  
    &lt;/div&gt;  
    &lt;div style=&quot;flex: 1;&quot;&gt;  
        &lt;h3 style=&quot;font-size: 1.5em; margin: 0 0 10px;&quot;&gt;Ready to Transform Your Work Area?&lt;/h3&gt;  
        &lt;p style=&quot;font-size: 1em; margin: 0 0 20px;&quot;&gt;Get started with FlowFuse&#39;s customizable 5S Checklist Blueprint and build your digital evaluation system in minutes.&lt;/p&gt;  
        &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/5s-checklist/&quot; class=&quot;cta-button&quot; style=&quot;display: inline-block; background-color:#4f46e5; color: #ffffff; padding: 8px 18px; text-decoration: none; border-radius: 9999px; font-weight: bold; font-size: 0.95em; transition: background-color 0.3s ease;&quot;&gt;Explore 5S Checklist Blueprint →&lt;/a&gt;  
    &lt;/div&gt;  
&lt;/div&gt; 
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/</id>
        <title>IT vs OT: Key Differences, Security Risks, and IT/OT Convergence</title>
        <summary>Two systems. Two priorities. One secure path to convergence.</summary>
        <updated>2025-09-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;IT vs OT is one of the most critical distinctions in modern manufacturing, representing two fundamentally different technology ecosystems: Information Technology (IT) and Operational Technology (OT). Understanding how these systems differ—and how to secure and integrate them—isn’t just a technical necessity. It’s a competitive advantage that prevents downtime, reduces cyber risk, and unlocks operational efficiency.&lt;/p&gt;
&lt;h2 id=&quot;what-is-information-technology-(it)%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#what-is-information-technology-(it)%3F&quot;&gt;What is Information Technology (IT)?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Information Technology encompasses the systems, software, and infrastructure that manage your business data and enable enterprise operations. IT systems handle everything from &lt;a href=&quot;https://flowfuse.com/node-red/notification/email/&quot;&gt;email&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/node-red/database/&quot;&gt;databases&lt;/a&gt; to enterprise resource planning (ERP), customer relationship management (CRM), and business intelligence platforms.&lt;/p&gt;
&lt;p&gt;Your IT infrastructure manages data storage and processing, enterprise communications like email and video conferencing, business applications for finance and accounting, and customer and supplier management systems. These systems increasingly rely on cloud services and software-as-a-service applications that enable flexible, scalable operations.&lt;/p&gt;
&lt;p&gt;The defining characteristics of IT systems reflect their business-oriented nature. They prioritize data confidentiality and integrity above all else, stay connected to external networks and the internet for collaboration and communication, and receive regular updates and patches on monthly or quarterly cycles. IT systems use standardized protocols like TCP/IP, HTTP, and HTTPS that enable straightforward connectivity. Most IT equipment has a typical lifecycle of three to five years before replacement, designed with flexibility and scalability as core requirements. When IT systems need maintenance, businesses can usually tolerate downtime measured in minutes to hours.&lt;/p&gt;
&lt;h2 id=&quot;what-is-operational-technology-(ot)%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#what-is-operational-technology-(ot)%3F&quot;&gt;What is Operational Technology (OT)?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Operational Technology refers to the hardware and software systems that monitor and control physical devices, processes, and infrastructure in industrial environments. OT directly manages your production operations, making it the backbone of manufacturing execution.&lt;/p&gt;
&lt;p&gt;OT systems include Industrial Control Systems (ICS), which serve as the umbrella term for all control systems used in industrial operations. Within this category, you&#39;ll find &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;Supervisory Control and Data Acquisition (SCADA)&lt;/a&gt; systems that provide centralized monitoring and control, &lt;a href=&quot;https://flowfuse.com/blog/2025/10/plc-to-mqtt-using-flowfuse/&quot;&gt;Programmable Logic Controllers (PLCs)&lt;/a&gt; that execute real-time control logic, and Distributed Control Systems (DCS) that manage complex continuous processes. &lt;a href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/&quot;&gt;Human-Machine Interfaces (HMI)&lt;/a&gt; provide operators with visualization and control capabilities, while Safety Instrumented Systems (SIS) protect people and equipment from hazardous conditions. Building Management Systems (BMS) and &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;Manufacturing Execution Systems (MES)&lt;/a&gt; round out the OT ecosystem.&lt;/p&gt;
&lt;p&gt;The characteristics of OT systems stand in stark contrast to IT. OT prioritizes safety, availability, and reliability above everything else. These systems were historically air-gapped or completely isolated from external networks, receiving infrequent updates—often annually or only when absolutely necessary during planned shutdowns. OT environments rely on proprietary and industrial protocols like &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Modbus&lt;/a&gt;, Profibus, &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;OPC-UA&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2025/10/using-ethernet-ip-with-flowfuse/&quot;&gt;EtherNet/IP&lt;/a&gt;, and DeviceNet rather than standard internet protocols. Equipment lifecycles stretch fifteen to twenty-five years in operation, designed for stability and deterministic performance rather than flexibility. In OT, downtime tolerance is essentially zero because every minute of stopped production directly costs money. Real-time processing happens in milliseconds, where timing precision can mean the difference between safe operation and catastrophic failure.&lt;/p&gt;
&lt;h2 id=&quot;it-vs-ot%3A-understanding-the-real-differences&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#it-vs-ot%3A-understanding-the-real-differences&quot;&gt;IT vs OT: Understanding the Real Differences&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Information Technology (IT) and Operational Technology (OT) are often discussed together, but they were created to solve very different problems. Before connecting these systems, it’s critical to understand where they differ and why those differences matter in real-world manufacturing environments.&lt;/p&gt;
&lt;p&gt;Simply put, &lt;strong&gt;IT manages information&lt;/strong&gt;, while &lt;strong&gt;OT controls physical processes&lt;/strong&gt;. IT systems support business operations such as finance, planning, communication, and analytics. OT systems directly run machines, production lines, and safety-critical infrastructure. Because OT interacts with the physical world, its requirements for reliability, timing, and safety are far stricter than those of IT systems.&lt;/p&gt;
&lt;p&gt;The table below summarizes the most important distinctions between IT and OT.&lt;/p&gt;
&lt;h2 id=&quot;it-vs-ot%3A-side-by-side-comparison&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#it-vs-ot%3A-side-by-side-comparison&quot;&gt;IT vs OT: Side-by-Side Comparison&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Information Technology (IT)&lt;/th&gt;
&lt;th&gt;Operational Technology (OT)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage business data and digital workflows&lt;/td&gt;
&lt;td&gt;Control and monitor physical equipment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Priority&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Efficiency, data integrity, and confidentiality&lt;/td&gt;
&lt;td&gt;Safety, availability, and reliability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operating Environment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Offices, data centers, cloud platforms&lt;/td&gt;
&lt;td&gt;Factory floors, plants, field locations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical Systems&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ERP, CRM, email, databases, cloud apps&lt;/td&gt;
&lt;td&gt;PLCs, SCADA, DCS, HMIs, SIS, MES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What Is Controlled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Information and processes&lt;/td&gt;
&lt;td&gt;Machines and industrial operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Impact of Downtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reduced productivity and service disruption&lt;/td&gt;
&lt;td&gt;Production stoppage and safety risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Downtime Tolerance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes to hours&lt;/td&gt;
&lt;td&gt;Near zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Response Time Requirements&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seconds to minutes&lt;/td&gt;
&lt;td&gt;Milliseconds to seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Lifecycle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3–5 years&lt;/td&gt;
&lt;td&gt;15–25+ years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Patch &amp;amp; Update Frequency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Regular and frequent&lt;/td&gt;
&lt;td&gt;Rare and carefully scheduled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Connectivity Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internet and cloud by default&lt;/td&gt;
&lt;td&gt;Historically isolated, now selectively connected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocols Used&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TCP/IP, HTTP/HTTPS, REST, SQL&lt;/td&gt;
&lt;td&gt;Modbus, OPC-UA, Profibus, EtherNet/IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Priority Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CIA&lt;/strong&gt;: Confidentiality → Integrity → Availability&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AIC&lt;/strong&gt;: Availability → Integrity → Confidentiality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Approach&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Patching, endpoint security, zero trust&lt;/td&gt;
&lt;td&gt;Segmentation, monitoring, minimal disruption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Change Management Style&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast and iterative&lt;/td&gt;
&lt;td&gt;Slow, controlled, and risk-averse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Consequences&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data loss or system outage&lt;/td&gt;
&lt;td&gt;Equipment damage, safety incidents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Regulatory Emphasis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data protection and compliance&lt;/td&gt;
&lt;td&gt;Safety and critical infrastructure protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical Skill Sets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;IT, networking, cybersecurity&lt;/td&gt;
&lt;td&gt;Automation, electrical, mechanical engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-growing-convergence-of-it-and-ot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#the-growing-convergence-of-it-and-ot&quot;&gt;The Growing Convergence of IT and OT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Historically, IT and OT operated in complete isolation. Your factory floor systems never touched corporate networks, and your business systems had no visibility into production processes. This separation provided natural security but created information silos that limited operational intelligence and prevented data-driven decision making.&lt;/p&gt;
&lt;p&gt;Today, Industry 4.0, the Industrial Internet of Things (IIoT), and smart manufacturing initiatives are driving unprecedented IT/OT convergence. Manufacturers are connecting production equipment to business systems to enable real-time production monitoring and analytics, predictive maintenance based on equipment data, automated supply chain integration, quality management with immediate feedback loops, and energy optimization across operations. Remote monitoring and control capabilities that were once impossible are now becoming standard expectations.&lt;/p&gt;
&lt;p&gt;This convergence is driven by shared goals that benefit from integration. Both IT and OT teams want operational efficiency and cost reduction, data-driven decision making, improved asset utilization, and enhanced quality control. Regulatory compliance and reporting requirements increasingly demand integrated data from both environments. Perhaps most compellingly, competitive advantage now flows from digital transformation that breaks down the walls between business and operational systems.&lt;/p&gt;
&lt;p&gt;Despite their differences, IT and OT systems share more similarities than many realize. Both require robust access controls and authentication mechanisms. Both generate valuable data for business insights when properly captured and analyzed. Both face increasing cybersecurity threats that demand attention. Both benefit from modern technologies like artificial intelligence, machine learning, and cloud computing. Both require skilled personnel for effective management and maintenance. And both are absolutely critical to business continuity—failure in either domain can cripple operations.&lt;/p&gt;
&lt;h2 id=&quot;the-critical-challenge%3A-cybersecurity-in-it%2Fot-convergence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#the-critical-challenge%3A-cybersecurity-in-it%2Fot-convergence&quot;&gt;The Critical Challenge: Cybersecurity in IT/OT Convergence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While IT/OT convergence delivers substantial benefits, it also creates significant cybersecurity risks. When you connect production systems to business networks—and potentially to the internet—you expose critical operational infrastructure to cyber threats that were previously impossible. Understanding these risks and implementing appropriate security measures isn&#39;t optional. It&#39;s essential for protecting your operations, your people, and your business.&lt;/p&gt;
&lt;h3 id=&quot;why-ot-security-differs-fundamentally-from-it-security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#why-ot-security-differs-fundamentally-from-it-security&quot;&gt;Why OT Security Differs Fundamentally from IT Security&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Traditional IT security assumptions simply don&#39;t apply in OT environments, creating dangerous gaps when IT security approaches are applied without modification. IT security relies heavily on regular patching and updates to address vulnerabilities. OT systems often can&#39;t be updated without production downtime, and some legacy equipment literally cannot be patched because vendors no longer support decades-old systems or the equipment lacks the computing resources for security updates.&lt;/p&gt;
&lt;p&gt;The availability versus confidentiality trade-off creates fundamental conflicts between IT and OT security priorities. IT security teams will gladly take systems offline to patch critical vulnerabilities or investigate potential breaches. OT security must prioritize system availability and safety above all else—a security measure that stops production or creates safety risks is worse than the threat it prevents. This isn&#39;t about OT teams being lax about security. It&#39;s about the reality that stopping a production line costs thousands of dollars per minute, and certain security measures could literally endanger human lives.&lt;/p&gt;
&lt;p&gt;System lifespan differences compound security challenges. IT equipment is replaced every few years, ensuring relatively current security capabilities. OT systems run for decades, meaning manufacturing facilities commonly operate equipment from the 1990s or early 2000s that was never designed with cybersecurity in mind. This equipment predates modern security threats and often lacks basic capabilities like encryption, authentication logging, or network security features.&lt;/p&gt;
&lt;p&gt;Real-time requirements in OT systems prevent the use of many standard IT security tools and techniques. OT systems control physical processes with millisecond timing requirements where deterministic behavior is critical. Security measures that introduce latency, even small amounts, can cause safety issues or production failures. Network scans, intrusion detection systems, and other IT security tools that work perfectly in business networks can inadvertently crash industrial controllers or disrupt critical timing.&lt;/p&gt;
&lt;p&gt;Legacy equipment presents perhaps the most intractable security challenge. Manufacturing facilities contain equipment from dozens of vendors spanning multiple decades. Much of this equipment was designed when industrial networks were completely isolated, so it has no security features whatsoever. Usernames and passwords might be hardcoded and unchangeable. Communications happen in cleartext with no encryption. These systems were built to last and they do their jobs perfectly—they just can&#39;t be secured using modern security practices.&lt;/p&gt;
&lt;h3 id=&quot;understanding-real-cybersecurity-threats-to-ot-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#understanding-real-cybersecurity-threats-to-ot-systems&quot;&gt;Understanding Real Cybersecurity Threats to OT Systems&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The threat landscape for OT environments is serious and growing. Ransomware attacks increasingly target manufacturing facilities because cybercriminals understand that production downtime pressure makes companies more likely to pay ransoms. A single ransomware attack can cost millions in downtime and recovery, even if no ransom is paid. Manufacturing targets are attractive because unlike IT systems where data can be restored from backups, stopping production creates immediate financial pain.&lt;/p&gt;
&lt;p&gt;Nation-state attacks represent sophisticated threats to critical infrastructure and manufacturing capabilities. State-sponsored actors seek to disrupt operations, steal intellectual property, or establish persistent access for future attacks. These attacks are often discovered only after months or years of presence in target networks, during which time attackers map systems, exfiltrate data, and position themselves for maximum impact.&lt;/p&gt;
&lt;p&gt;Insider threats from disgruntled employees or contractors with access to OT systems can cause significant damage through malicious action or negligent behavior. Someone with legitimate access and knowledge of industrial systems can bypass security controls that would stop external attackers. The damage can range from sabotage of production systems to theft of proprietary processes and formulations.&lt;/p&gt;
&lt;p&gt;Supply chain compromises introduce vulnerabilities through third-party equipment, software, or vendor access. When a vendor&#39;s remote access credentials are compromised, attackers gain legitimate pathways into OT environments. Equipment may ship with malware pre-installed or contain undisclosed backdoors. Software updates from trusted vendors can be compromised to distribute malware to multiple customers simultaneously.&lt;/p&gt;
&lt;p&gt;Perhaps ironically, unintentional disruptions from well-meaning IT actions cause frequent problems. IT security scans or updates applied to OT networks can inadvertently crash industrial systems that can&#39;t handle the traffic patterns or protocol variations. A network scan that&#39;s routine for IT systems might overwhelm a PLC that was never designed to handle that volume or type of network traffic.&lt;/p&gt;
&lt;h3 id=&quot;implementing-effective-ot%2Fit-security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#implementing-effective-ot%2Fit-security&quot;&gt;Implementing Effective OT/IT Security&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Network segmentation provides the foundational defense for converged IT/OT environments. Implementing defense-in-depth architecture with clear separation between IT and OT networks prevents threats from freely moving between environments. Industrial DMZs (demilitarized zones) control data flow between environments through strictly managed interfaces. The cardinal rule: never allow direct connectivity from the internet to OT networks, regardless of business pressure or convenience arguments.&lt;/p&gt;
&lt;p&gt;Asset inventory and visibility seem basic but prove surprisingly challenging in practice. Maintaining comprehensive inventories of all OT assets including hardware specifications, software versions, communication protocols, and system dependencies requires ongoing effort. Shadow IT in OT—unauthorized equipment connected to industrial networks—creates unknown vulnerabilities. You cannot secure what you don&#39;t know exists, making discovery and inventory continuous processes rather than one-time projects.&lt;/p&gt;
&lt;p&gt;Access control and authentication require careful implementation that balances security with operational requirements. Role-based access controls with the principle of least privilege ensure people can do their jobs but nothing more. Multi-factor authentication for remote access adds protection without adding excessive friction for legitimate users. Regular reviews of access permissions catch orphaned accounts and excessive privileges that accumulate over time.&lt;/p&gt;
&lt;p&gt;Industrial security monitoring deploys OT-specific security tools that understand industrial protocols and can detect anomalous behavior without disrupting operations. Traditional IT security tools often aren&#39;t appropriate for OT environments because they don&#39;t understand industrial protocols, introduce unacceptable latency, or generate false positives that create alert fatigue. Purpose-built industrial security platforms can monitor traffic, detect threats, and alert security teams while respecting OT&#39;s unique requirements.&lt;/p&gt;
&lt;p&gt;Vendor and third-party management controls one of the largest attack surfaces in OT environments. Carefully controlling vendor access to OT systems through jump servers, time-limited credentials, and continuous monitoring protects against both malicious actors and accidental damage. Every remote access session should be logged and auditable. Vendors should access only the specific systems they need, not entire network segments.&lt;/p&gt;
&lt;p&gt;Backup and recovery planning takes on special importance in OT environments. Maintaining offline backups of critical OT configurations, PLC programs, HMI setups, and system documentation enables recovery when systems are compromised or fail. Testing recovery procedures regularly ensures they work when needed, because restoring OT systems is fundamentally different from IT recovery. You can&#39;t simply restore from last night&#39;s backup if that backup is months old or doesn&#39;t include the custom programming that makes your production line run.&lt;/p&gt;
&lt;p&gt;Security awareness training must address the unique requirements of converged environments. IT staff need to understand OT constraints including real-time requirements, change management processes, and why their normal security tools can&#39;t be used without modification. OT staff need to understand cybersecurity fundamentals including threat landscapes, attack vectors, and security best practices. Building mutual understanding between IT and OT teams prevents dangerous assumptions and enables effective collaboration.&lt;/p&gt;
&lt;p&gt;Regulatory compliance provides frameworks and requirements for industrial security. Industry-specific standards like IEC 62443 for industrial automation security, NERC-CIP for critical infrastructure protection, and NIST Cybersecurity Framework guidance for industrial systems establish baseline security practices. Compliance isn&#39;t just about checking boxes—these standards codify lessons learned from incidents across industries and provide structured approaches to industrial security.&lt;/p&gt;
&lt;h2 id=&quot;technical-deep-dive%3A-core-ot-technologies&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#technical-deep-dive%3A-core-ot-technologies&quot;&gt;Technical Deep Dive: Core OT Technologies&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial Control Systems (ICS) serves as the umbrella term for all control systems used in industrial operations. ICS includes SCADA systems, distributed control systems, programmable logic controllers, and related technologies that monitor and control industrial processes across manufacturing, energy production, water treatment, chemical processing, and critical infrastructure sectors. Understanding ICS architecture and components is essential for securing and integrating OT environments.&lt;/p&gt;
&lt;p&gt;SCADA systems provide supervisory control and data acquisition for geographically distributed processes. A SCADA system might monitor and control water treatment across an entire city, manage electrical generation and distribution across a region, or coordinate production across multiple manufacturing facilities. SCADA systems collect data from remote locations, provide centralized visualization and control, generate alarms when conditions exceed thresholds, and log historical data for analysis and compliance. Modern SCADA platforms increasingly integrate with IT systems for advanced analytics and business intelligence.&lt;/p&gt;
&lt;p&gt;Programmable Logic Controllers (PLCs) execute real-time control logic at the machine and process level. These ruggedized industrial computers run specialized programs that read sensors, make decisions based on programmed logic, and control actuators and equipment. PLCs operate in harsh industrial environments with extreme temperatures, vibration, electrical noise, and contamination that would destroy standard computers. They provide deterministic execution where timing is guaranteed, ensuring safety and process control requirements are met. PLCs use ladder logic, function block diagrams, or structured text programming languages designed for industrial applications rather than general-purpose computing.&lt;/p&gt;
&lt;p&gt;Distributed Control Systems (DCS) manage complex continuous processes like chemical production, oil refining, or power generation. Unlike SCADA systems that supervise distributed operations, DCS provides integrated control of processes within a single facility. DCS architecture distributes control functions across multiple controllers for redundancy and performance, integrates control, operator interfaces, and engineering tools in unified platforms, and manages complex regulatory control strategies for maintaining product quality and process efficiency. DCS platforms represent significant investments with lifecycles often exceeding twenty years.&lt;/p&gt;
&lt;p&gt;Human-Machine Interfaces (HMI) provide the visualization and control capabilities that operators use to monitor and manage industrial processes. Modern HMIs display real-time process data through graphics, trends, and alarms, enable operators to adjust setpoints and control equipment, provide historical trending and reporting capabilities, and increasingly support mobile access for remote monitoring. HMI design significantly affects operator effectiveness and safety, making usability and information clarity critical considerations.&lt;/p&gt;
&lt;h2 id=&quot;industrial-protocols%3A-the-languages-of-ot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#industrial-protocols%3A-the-languages-of-ot&quot;&gt;Industrial Protocols: The Languages of OT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial protocols enable communication between OT devices but differ fundamentally from standard IT protocols. Modbus, developed in 1979, remains widely used for connecting industrial electronic devices. This simple, robust protocol enables PLCs, sensors, and other devices to communicate over serial connections or Ethernet networks. Modbus&#39;s age means it has no built-in security features—all communications are unencrypted and unauthenticated—but its ubiquity and simplicity ensure it will remain deployed for decades.&lt;/p&gt;
&lt;p&gt;Profibus and Profinet serve as standard protocols in European manufacturing and are particularly common in automotive and process industries. Profibus operates over serial connections while Profinet runs on standard Ethernet, providing faster communications and more features. These Siemens-developed protocols dominate in certain industries and regions, creating integration challenges when connecting equipment from different vendors.&lt;/p&gt;
&lt;p&gt;OPC-UA (OLE for Process Control - Unified Architecture) represents a modern, secure, and platform-independent protocol designed for industrial interoperability. Unlike older protocols, OPC-UA includes built-in security features including encryption, authentication, and authorization. It enables semantic modeling of industrial data so systems understand not just values but their meaning and relationships. OPC-UA is increasingly adopted as the standard for Industry 4.0 and IIoT applications because it addresses both connectivity and security requirements.&lt;/p&gt;
&lt;p&gt;EtherNet/IP adapts standard Ethernet and TCP/IP protocols for industrial automation, particularly in North American manufacturing. This protocol is common in discrete manufacturing, packaging, and material handling applications. DeviceNet provides a low-cost network for connecting simple industrial devices like sensors, motor starters, and actuators to PLCs and controllers.&lt;/p&gt;
&lt;p&gt;The diversity of industrial protocols creates significant integration challenges. A single manufacturing facility might use half a dozen different protocols across equipment from various vendors and vintages. Protocol converters, gateways, and translation tools are often necessary to achieve connectivity, adding complexity and potential points of failure. This protocol fragmentation makes unified &lt;a href=&quot;https://flowfuse.com/solutions/it-ot-middleware/&quot;&gt;IT/OT integration&lt;/a&gt; technically challenging and expensive.&lt;/p&gt;
&lt;h2 id=&quot;the-organizational-challenge%3A-bridging-it-and-ot-teams&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#the-organizational-challenge%3A-bridging-it-and-ot-teams&quot;&gt;The Organizational Challenge: Bridging IT and OT Teams&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Technical integration challenges are matched by organizational and cultural differences between IT and OT teams. These groups often have fundamentally different priorities, training, and approaches to problems, creating friction that can derail integration projects if not addressed thoughtfully.&lt;/p&gt;
&lt;p&gt;IT teams focus on keeping business systems running, securing data, enabling collaboration, and adopting new technologies to improve business processes. They&#39;re accustomed to regular change, view updates and patches as routine and necessary, prioritize cybersecurity and data protection, and measure success through system availability, user satisfaction, and cost efficiency. IT professionals typically have formal education in computer science or information systems and hold certifications like CISSP, CISM, or various vendor credentials.&lt;/p&gt;
&lt;p&gt;OT teams focus on keeping production running safely and efficiently, maintaining equipment reliability, preventing unplanned downtime, and preserving process knowledge that might span decades. They&#39;re accustomed to stability and view changes with skepticism until proven necessary, prioritize safety and availability over all other concerns, and measure success through production uptime, quality metrics, and safety records. OT professionals often come from engineering backgrounds in electrical, mechanical, or chemical engineering, holding certifications like PE licenses or vendor-specific industrial automation credentials.&lt;/p&gt;
&lt;p&gt;These different backgrounds create predictable conflicts. When IT suggests network upgrades or security improvements, OT worries about production disruption and unproven technology in critical systems. When OT wants to keep running proven systems unchanged, IT worries about security vulnerabilities and inability to integrate with modern business systems. Both perspectives are valid and rooted in real concerns shaped by each team&#39;s responsibilities and past experiences.&lt;/p&gt;
&lt;p&gt;Successful IT/OT convergence requires building bridges between these cultures. Creating cross-functional teams that include both IT and OT expertise ensures projects consider all relevant concerns from the beginning. Establishing shared goals and metrics that both teams contribute to helps align priorities. Developing mutual respect through education about each domain&#39;s challenges and constraints builds understanding. And perhaps most importantly, ensuring executive leadership understands and supports convergence efforts provides the authority and resources necessary to overcome organizational inertia.&lt;/p&gt;
&lt;h2 id=&quot;making-it%2Fot-convergence-work%3A-strategic-implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#making-it%2Fot-convergence-work%3A-strategic-implementation&quot;&gt;Making IT/OT Convergence Work: Strategic Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Successful IT/OT convergence requires a strategic, methodical approach rather than ad-hoc connectivity projects. Start by establishing clear business objectives that justify the effort and investment. What specific problems are you trying to solve? What measurable outcomes define success? IT/OT convergence is a means to an end, not an end in itself, so clarity about the desired outcomes guides all subsequent decisions.&lt;/p&gt;
&lt;p&gt;Prioritize use cases with measurable return on investment to build momentum and prove value. Rather than attempting comprehensive integration all at once, identify specific high-value opportunities where connectivity delivers clear benefits. Predictive maintenance that prevents unplanned downtime, real-time quality monitoring that reduces scrap, or energy optimization that lowers utility costs provide concrete value propositions. Success with focused use cases builds organizational confidence and provides lessons for broader implementation.&lt;/p&gt;
&lt;p&gt;Design robust security architectures from the beginning rather than adding security as an afterthought. The security model must respect OT constraints while providing effective protection. This typically involves network segmentation with industrial DMZs, defense-in-depth strategies with multiple security layers, OT-specific security monitoring and threat detection, and carefully managed interfaces between IT and OT environments. Security architecture decisions made early are difficult and expensive to change later.&lt;/p&gt;
&lt;p&gt;Foster collaboration between IT and OT teams through shared projects, cross-training, and integrated planning. The technical integration cannot succeed without organizational integration. Create forums for regular communication between teams, establish joint governance for converged systems, and develop shared understanding of each domain&#39;s requirements and constraints. Successful convergence projects consistently cite strong IT/OT collaboration as a critical success factor.&lt;/p&gt;
&lt;p&gt;Plan for long-term evolution rather than one-time projects. IT/OT convergence is an ongoing journey as technology, business requirements, and threat landscapes evolve. Build flexible architectures that can adapt to changing needs, establish processes for continuous improvement, and plan for lifecycle management of integrated systems. The goal isn&#39;t reaching a finished state but rather creating capabilities for continuous adaptation and improvement.&lt;/p&gt;
&lt;h2 id=&quot;real-world-benefits-of-it%2Fot-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#real-world-benefits-of-it%2Fot-integration&quot;&gt;Real-World Benefits of IT/OT Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When implemented thoughtfully, IT/OT convergence delivers substantial operational and business benefits. Production visibility transforms from lagging indicators based on end-of-shift reports to real-time dashboards that show current performance, immediate quality metrics, and live equipment status. This visibility enables faster problem identification and response, data-driven decision making at all organizational levels, and immediate understanding of production impacts from changes.&lt;/p&gt;
&lt;p&gt;Predictive maintenance shifts maintenance strategies from reactive repairs or time-based schedules to condition-based maintenance driven by actual equipment health. Sensors and analytics identify early warning signs of impending failures, allowing maintenance during planned downtime rather than crisis response to breakdowns. This reduces unplanned downtime, extends equipment life through optimal maintenance timing, and lowers maintenance costs through better resource allocation.&lt;/p&gt;
&lt;p&gt;Quality management improves through immediate feedback loops that connect production processes with quality results. Rather than discovering defects in finished goods or during sampling, integrated systems can detect quality excursions in real-time and automatically adjust processes or alert operators. This reduces scrap and rework, improves first-pass yield, and enables faster root cause analysis when issues occur.&lt;/p&gt;
&lt;p&gt;Energy optimization becomes possible when business systems can analyze energy consumption patterns across production operations. Identifying energy-intensive processes, optimizing production schedules to leverage time-of-use rates, and detecting energy waste from inefficient equipment operation deliver measurable cost reductions. Many manufacturers discover that previously invisible energy waste represents significant savings opportunities.&lt;/p&gt;
&lt;p&gt;Supply chain integration becomes more dynamic and responsive when production systems can communicate directly with inventory, purchasing, and logistics systems. Automated reordering triggered by actual consumption rather than forecasts, real-time visibility of production status for customer order management, and immediate coordination of material delivery with production schedules reduce inventory carrying costs while improving delivery performance.&lt;/p&gt;
&lt;h2 id=&quot;common-pitfalls-to-avoid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#common-pitfalls-to-avoid&quot;&gt;Common Pitfalls to Avoid&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding common implementation failures helps organizations avoid costly mistakes. The single biggest pitfall is treating IT/OT convergence purely as a technology project rather than a strategic business initiative. Without clear business objectives and executive sponsorship, projects devolve into technical exercises that may achieve connectivity but deliver limited business value. Secure executive commitment to desired business outcomes before beginning significant integration work.&lt;/p&gt;
&lt;p&gt;Underestimating security requirements leads to vulnerable implementations that expose critical operations to cyber threats. Organizations sometimes focus on achieving connectivity while treating security as something to address later. In IT/OT convergence, security must be architectural rather than bolted on afterward. The cost and complexity of retrofitting security after deployment far exceeds incorporating it from the beginning.&lt;/p&gt;
&lt;p&gt;Ignoring legacy equipment challenges causes projects to stall when teams encounter the reality of decades-old systems that can&#39;t be integrated using modern approaches. Assess the actual state of existing equipment early in planning, identify systems that will require special handling or replacement, and budget accordingly. Many legacy systems can be integrated through edge devices or protocol converters, but this requires planning and investment.&lt;/p&gt;
&lt;p&gt;Failing to involve OT teams in planning and implementation creates resistance and risks disrupting production. IT-led initiatives that treat OT as simply another network to be managed often fail because they don&#39;t account for OT&#39;s unique requirements and constraints. Successful projects include OT expertise from the beginning and respect the primacy of production operations.&lt;/p&gt;
&lt;p&gt;Attempting too much too quickly overwhelms organizations and dilutes resources across multiple initiatives. Better to achieve significant success with focused use cases than superficial progress across broad initiatives. Build momentum through early wins rather than comprehensive transformation attempts.&lt;/p&gt;
&lt;h2 id=&quot;your-path-forward-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/it-vs-ot-difference-between-information-technology-and-operational-technology/#your-path-forward-with-flowfuse&quot;&gt;Your Path Forward with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Navigating IT/OT convergence requires tools that understand both worlds. FlowFuse is built on &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt;, an open-source platform that has become the de facto standard for industrial integration, with over &lt;a href=&quot;https://flowfuse.com/integrations/&quot;&gt;5,000 pre-built&lt;/a&gt; nodes connecting to industrial protocols, databases, cloud platforms, and business systems. This extensive library means you can integrate Modbus devices with your ERP system, connect OPC-UA machines to cloud analytics, or bridge SCADA systems with business intelligence tools—all without extensive custom programming.&lt;/p&gt;
&lt;p&gt;The visual, drag-and-drop interface enables your engineers and technicians to build integration workflows directly. People who understand your processes and equipment can implement solutions themselves, reducing dependency on external developers and speeding project delivery. This democratization of integration development means OT teams aren&#39;t dependent on IT resources for every connection or modification.&lt;/p&gt;
&lt;p&gt;FlowFuse adds enterprise capabilities including team collaboration, version control, and secure deployment to the Node-RED foundation. These features make Node-RED suitable for production manufacturing environments where change management, security, and reliability are non-negotiable. Projects can be developed in test environments, reviewed by stakeholders, and deployed to production with confidence.&lt;/p&gt;
&lt;p&gt;Security features built into FlowFuse protect your integration projects and the systems they connect. Role-based access controls ensure people can access only appropriate projects and deployments. Audit logging provides visibility into changes and activities. Network isolation options enable proper segmentation between IT and OT environments even within your integration platform.&lt;/p&gt;
&lt;p&gt;The open-source foundation means you&#39;re never locked into proprietary technology or single-vendor solutions. Node-RED&#39;s active community continuously develops new protocol support, integration capabilities, and functionality. When you need to connect to new equipment or systems, chances are someone has already created the necessary integration components.&lt;/p&gt;
&lt;p&gt;Manufacturing operations worldwide rely on FlowFuse for IT/OT convergence projects ranging from simple data collection to sophisticated predictive maintenance, quality management, and energy optimization initiatives. The platform scales from proof-of-concept projects to enterprise deployments managing thousands of devices and processes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo today&lt;/a&gt; to see how FlowFuse can help you navigate IT/OT convergence securely and effectively, using proven open-source technology that respects both IT and OT requirements.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/</id>
        <title>Preventive Maintenance in Manufacturing: Avoid Multi-Million Dollar Equipment Failures</title>
        <summary>How industrial data platforms are turning equipment failures from crisis events into predictable, manageable costs</summary>
        <updated>2025-09-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;At 2:47 AM on a Tuesday, a $15 bearing brought down a $2 million production line.&lt;/p&gt;
&lt;p&gt;While this specific incident is illustrative, the failure pattern it represents is all too real and systemic. According to recent industry research, unplanned downtime outages last an average of four hours and cost an average of $2 million per incident. These bearing failures happen across manufacturing facilities worldwide with predictable consistency: emergency repairs, overtime labor, expedited parts, delayed customer orders, and relationship damage. All from a component that could have been replaced during scheduled downtime for $800.&lt;/p&gt;
&lt;p&gt;The real tragedy? Every signal was there. Vibration readings had climbed 40% over six weeks. Temperature spikes occurred during peak loads. Acoustic signatures screamed impending failure. But without systematic monitoring, these warnings vanished into the noise of daily operations.&lt;/p&gt;
&lt;p&gt;This isn&#39;t a maintenance story, it&#39;s a data story. And it&#39;s playing out in manufacturing facilities worldwide every day. According to Forbes, unplanned downtime can cost manufacturing companies a whopping $50 billion per year. Siemens&#39; 2024 report reveals that unplanned downtime now costs Fortune Global 500 companies 11% of their yearly turnover, almost $1.5 trillion, up from $864 billion two years ago.&lt;/p&gt;
&lt;h2 id=&quot;the-predictable-science-of-equipment-death&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#the-predictable-science-of-equipment-death&quot;&gt;The Predictable Science of Equipment Death&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Equipment failures aren&#39;t random disasters, they&#39;re predictable processes that unfold over weeks or months, leaving digital breadcrumbs that reveal exactly when intervention will be most cost-effective.&lt;/p&gt;
&lt;p&gt;Reliability engineers call this the P-F curve: the measurable interval between when a potential failure (P) becomes detectable and functional failure (F) occurs. For rotating equipment like motors and pumps, this window typically spans 6-12 weeks. For hydraulic systems, 2-8 weeks. For electronic components, days to months.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;P-F Curve.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pf-curve.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;P-F Curve.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;During this P-F interval, equipment broadcasts its distress through dozens of measurable parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vibration patterns&lt;/strong&gt; shift as bearings wear and alignments drift&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Power consumption&lt;/strong&gt; increases as friction rises and efficiency drops&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temperature profiles&lt;/strong&gt; change as lubricants degrade and clearances widen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acoustic signatures&lt;/strong&gt; evolve as mechanical tolerances exceed design limits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Process variables&lt;/strong&gt; drift as equipment performance degrades&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The math is brutal. According to research by Eptura, on-demand work orders generally take twice as long as preventive maintenance, cutting associated labor costs in half through proactive approaches. A comprehensive study by JLL (Jones Lang LaSalle) analyzing 14 million square feet of mixed building types found that preventive maintenance produces an astounding 545% return on investment.&lt;/p&gt;
&lt;h2 id=&quot;why-over-half-of-manufacturers-still-play-failure-roulette&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#why-over-half-of-manufacturers-still-play-failure-roulette&quot;&gt;Why Over Half of Manufacturers Still Play Failure Roulette&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite overwhelming evidence favoring preventive approaches, many facilities still operate critical equipment on run-to-failure strategies. The reason isn&#39;t ignorance, it&#39;s infrastructure complexity and historical implementation challenges.&lt;/p&gt;
&lt;p&gt;Traditional preventive maintenance software promised comprehensive monitoring but delivered integration nightmares. Each device required custom programming, proprietary gateways, and specialized expertise. Implementation projects stretched 12-18 months, cost hundreds of thousands of dollars, and often failed to deliver promised capabilities.&lt;/p&gt;
&lt;p&gt;Meanwhile, production environments grew increasingly complex. A single line now might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1990s CNC machines speaking serial protocols&lt;/li&gt;
&lt;li&gt;2000s PLCs using Modbus communication&lt;/li&gt;
&lt;li&gt;2010s robots on Ethernet/IP networks&lt;/li&gt;
&lt;li&gt;2024 sensors transmitting via MQTT and other IoT protocols&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each system operates in isolation, generating valuable data that remains trapped behind incompatible interfaces.&lt;/p&gt;
&lt;h2 id=&quot;the-platform-revolution%3A-universal-data%2C-unified-insights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#the-platform-revolution%3A-universal-data%2C-unified-insights&quot;&gt;The Platform Revolution: Universal Data, Unified Insights&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modern industrial data platforms are eliminating these barriers by treating connectivity as a solved problem rather than a custom project.&lt;/p&gt;
&lt;p&gt;Instead of requiring expensive integration for each device type, these platforms provide universal connectivity out of the box. Legacy equipment, modern sensors, and everything in between can communicate through a single interface without gateways, converters, or custom programming.&lt;/p&gt;
&lt;p&gt;This fundamental shift changes the economics of comprehensive monitoring. Instead of monitoring a few critical machines with dedicated systems, manufacturers can monitor everything, from primary production equipment to auxiliary systems like compressed air, HVAC, and power distribution.&lt;/p&gt;
&lt;p&gt;Research indicates that 95% of predictive maintenance adopters reported a positive ROI, with 27% of these reporting amortization in less than a year.&lt;/p&gt;
&lt;h2 id=&quot;evidence-based-results-from-leading-manufacturers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#evidence-based-results-from-leading-manufacturers&quot;&gt;Evidence-Based Results from Leading Manufacturers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The transformation from reactive to predictive maintenance is delivering measurable results across industries:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automotive Manufacturing:&lt;/strong&gt; Major automotive suppliers have achieved 50% reduction in unplanned downtime after implementing comprehensive equipment monitoring across their facilities. The key wasn&#39;t just monitoring critical assets, it was monitoring everything, creating a complete picture of facility health.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Electronics Production:&lt;/strong&gt; Leading electronics manufacturers report 25% reduction in maintenance costs by connecting previously isolated systems on unified data platforms. Maintenance teams can finally see relationships between equipment performance and environmental factors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Industrial Equipment:&lt;/strong&gt; According to the U.S. Department of Energy, predictive maintenance helps enterprises gain remarkable results such as a tenfold increase in ROI, 70-75% decrease in breakdowns, 25-30% reduction in costs, and 35-45% reduction in downtime.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-the-open%2C-scalable%2C-and-flexible-industrial-data-platform&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#flowfuse%3A-the-open%2C-scalable%2C-and-flexible-industrial-data-platform&quot;&gt;FlowFuse: The Open, Scalable, and Flexible Industrial Data Platform&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse represents the next evolution in industrial data platforms, designed by engineers who understand both the promise and frustrations of traditional systems.&lt;/p&gt;
&lt;p&gt;Built on Node-RED, the open-source standard for industrial connectivity, FlowFuse eliminates integration barriers that have historically made comprehensive monitoring expensive and complex. Native support for almost all industrial protocols and systems means any device that communicates digitally can connect without custom development.&lt;/p&gt;
&lt;p&gt;But connectivity is just the foundation. FlowFuse&#39;s visual programming environment enables engineers to build sophisticated monitoring applications using drag-and-drop interfaces. Need to correlate motor vibration with production load? Create custom dashboards for different user roles? Set up automated alerts based on complex conditions? All possible without writing code.&lt;/p&gt;
&lt;p&gt;The platform&#39;s AI-powered editor goes further by reducing the development effort for engineers.&lt;/p&gt;
&lt;p&gt;For enterprise users, FlowFuse provides several essential features to support large-scale, collaborative, and secure industrial data operations. This includes DevOps tools and Remote Device Management, which streamline the deployment of applications and allow teams to remotely monitor and update their connected devices. To facilitate teamwork and project management, the platform incorporates Snapshot &amp;amp; Version Control and Real-Time Team Collaboration, enabling multiple people to work together on projects and easily track changes. For system reliability, FlowFuse offers High Availability, and to simplify user access while boosting security, it provides Single Sign-On (SSO). Additionally, Role-Based Access Control is a key security feature that lets administrators manage and restrict data access for different users.&lt;/p&gt;
&lt;p&gt;Most importantly, FlowFuse uses transparent pricing that encourages comprehensive data collection. No per-tag penalties, no volume restrictions, just straightforward costs that scale with business value rather than data points monitored.&lt;/p&gt;
&lt;h2 id=&quot;the-new-maintenance-economics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#the-new-maintenance-economics&quot;&gt;The New Maintenance Economics&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Companies implementing comprehensive equipment monitoring through modern data platforms are rewriting the economics of manufacturing operations. The financial picture changes almost immediately: emergency repairs drop by as much as &lt;strong&gt;60–80%&lt;/strong&gt; as failures shift from unexpected crises to planned interventions. Overall maintenance spending falls by &lt;strong&gt;12–18%&lt;/strong&gt; as teams allocate resources more efficiently, while spare parts inventories shrink by &lt;strong&gt;30–50%&lt;/strong&gt; because demand becomes predictable rather than chaotic.&lt;/p&gt;
&lt;p&gt;The impact extends well beyond cost savings. Equipment life stretches by &lt;strong&gt;20–40%&lt;/strong&gt; when replacement is driven by condition rather than arbitrary schedules. Overall Equipment Effectiveness (OEE) climbs by &lt;strong&gt;10–20%&lt;/strong&gt; as downtime disappears from production schedules, and energy consumption drops by &lt;strong&gt;5–15%&lt;/strong&gt; as machines run closer to their designed efficiency.&lt;/p&gt;
&lt;p&gt;Operational excellence amplifies across the board. Companies see on-time delivery rates climb past &lt;strong&gt;95%&lt;/strong&gt;, far outpacing the industry average of 75% in reactive environments. Customer satisfaction rises in parallel, supported by the reliability of consistent delivery. Workforce safety also improves as proactive monitoring identifies hazards before they escalate.&lt;/p&gt;
&lt;p&gt;According to research by &lt;strong&gt;McKinsey &amp;amp; Company&lt;/strong&gt;, the cumulative effect of these improvements is profound: organizations that adopt data-driven decision making are on average &lt;strong&gt;5% more productive&lt;/strong&gt; and &lt;strong&gt;6% more profitable&lt;/strong&gt; than competitors who remain locked in reactive cycles.&lt;/p&gt;
&lt;h2 id=&quot;the-implementation-reality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#the-implementation-reality&quot;&gt;The Implementation Reality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The path from reactive to proactive maintenance is clearer than ever, but success requires more than software selection, it requires cultural transformation.&lt;/p&gt;
&lt;p&gt;Start with pain point identification. Which equipment failures cause the most disruption? Where are emergency repair costs highest? What assets have the longest replacement lead times? These become your monitoring priorities.&lt;/p&gt;
&lt;p&gt;Focus on quick wins that build organizational confidence. Monitor 3-5 critical assets that represent different failure modes and equipment types. Establish baselines, implement basic condition monitoring, and measure results rigorously.&lt;/p&gt;
&lt;p&gt;The US Department of Energy reports a projected ROI of ten times the investment for organizations implementing predictive maintenance strategies.&lt;/p&gt;
&lt;p&gt;Most importantly, treat this as a capability-building exercise, not a technology project. The goal isn&#39;t just preventing failures, it&#39;s developing organizational competencies in data-driven decision making that enable continuous operational improvement.&lt;/p&gt;
&lt;h2 id=&quot;taking-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#taking-action&quot;&gt;Taking Action&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The business case is overwhelming. The technology barriers are eliminated. The competitive advantages are clear and measurable.&lt;/p&gt;
&lt;p&gt;The question isn&#39;t whether to implement comprehensive equipment monitoring, it&#39;s how quickly you can build capabilities that deliver sustainable competitive advantages.&lt;/p&gt;
&lt;p&gt;Calculate your current failure costs honestly. Include not just repair expenses but lost production, customer impact, and opportunity costs. Identify your most critical assets and pain points. Evaluate platforms that provide universal connectivity without integration complexity.&lt;/p&gt;
&lt;p&gt;The manufacturers moving decisively are gaining first-mover advantages in operational excellence that their competitors will struggle to match. Those delaying risk permanent disadvantage in an increasingly data-driven industry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ready to transform equipment failures from crisis events into predictable costs?&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Discover how FlowFuse enables comprehensive equipment monitoring&lt;/a&gt; that delivers measurable competitive advantages from day one.&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/preventive-maintenance-equipment-failure/#references&quot;&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;TeamSense (2024). &lt;em&gt;High Cost of Downtime in Manufacturing &amp;amp; How to Reduce It&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;IIoT World (2023). &lt;em&gt;The Actual Cost of Downtime in Manufacturing&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Evocon (2024). &lt;em&gt;Cost of Downtime in Manufacturing: Insights &amp;amp; Implications&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;IDS Data (2025). &lt;em&gt;The Real Cost of Downtime in Manufacturing&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Eptura (2025). &lt;em&gt;Workplace Index: Preventive Maintenance ROI&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;IoT Analytics (2024). &lt;em&gt;Predictive Maintenance Market: 5 Highlights&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Polaris Market Research (2024). &lt;em&gt;Predictive Maintenance Market Report, 2024–2032&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;MoldStud (2024). &lt;em&gt;ROI Benefits of Predictive Maintenance&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Sensorfy (2023). &lt;em&gt;How to Calculate Predictive Maintenance ROI&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;MicroMain (2024). &lt;em&gt;Preventive Maintenance ROI of 545%&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;ScienceDirect (2025). &lt;em&gt;Systematic Review of Predictive Maintenance Practices&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;IIoT World (2024). &lt;em&gt;Predictive Maintenance: Hidden ROI Driver&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Additional references: U.S. Department of Energy (predictive maintenance effectiveness), McKinsey &amp;amp; Company (productivity studies), Siemens (True Cost of Downtime reports).&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/09/creating-pareto-chart/</id>
        <title>How to Create a Pareto Chart for Manufacturing Data</title>
        <summary>Transform Raw Production Data into Actionable Insights with a Visual Pareto Analysis</summary>
        <updated>2025-09-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/09/creating-pareto-chart/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In the &lt;a href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/&quot;&gt;first part of this series&lt;/a&gt;, we explored the foundational principles of the Pareto Chart, understanding how this powerful tool can help manufacturing teams quickly identify and focus on the &amp;quot;vital few&amp;quot; problems that have the biggest impact. We learned that by combining a bar graph and a cumulative percentage line, a Pareto Chart provides a clear visual roadmap to prioritize quality issues, equipment downtime, or other key performance indicators.&lt;/p&gt;
&lt;p&gt;Now, it&#39;s time to move from theory to practice. This guide will show you how to create a Pareto Chart using modern industrial data tools. You will learn how to connect to your production data, calculate frequencies and format data, and visualize the results in a chart that helps your team make data-driven decisions.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Pareto Chart showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pareto-chart.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Pareto Chart showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To create a Pareto Chart for manufacturing data, you&#39;ll need access to industrial data platforms that can connect to your production systems. This guide uses FlowFuse, a low-code platform that simplifies industrial data workflows. If you don&#39;t have an account yet, you can &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;sign up for a 14-day free trial&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-connect-to-your-data-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#step-1%3A-connect-to-your-data-source&quot;&gt;Step 1: Connect to Your Data Source&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step to create a Pareto Chart is accessing the data you want to analyze. In industrial environments, machine or process data is commonly collected via &lt;a href=&quot;https://flowfuse.com/node-red/protocol/&quot;&gt;industrial protocols&lt;/a&gt; such as &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;OPC-UA&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt;, or direct &lt;a href=&quot;https://flowfuse.com/node-red/database/&quot;&gt;database&lt;/a&gt; queries. Modern industrial platforms support nearly all industrial protocols and databases, making it easy to connect to your existing systems.&lt;/p&gt;
&lt;p&gt;To connect your data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the appropriate input node into your flow (e.g., an OPC-UA Read node).&lt;/li&gt;
&lt;li&gt;Enter the connection details for your industrial system.&lt;/li&gt;
&lt;li&gt;Test the connection to confirm that live data is flowing correctly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a live PLC or factory dataset is not available, you can use a simple Inject node to simulate production data and learn how to make a Pareto Chart with sample data.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-format-and-aggregate-the-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#step-2%3A-format-and-aggregate-the-data&quot;&gt;Step 2: Format and Aggregate the Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once data is flowing, the next step to create a Pareto Chart is to &lt;strong&gt;organize it into types or categories and count how often each occurs&lt;/strong&gt;. A Pareto Chart is most useful when you can clearly see, for example, defect data like:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Scratch on Surface – 20 occurrences, Misaligned Parts – 10 occurrences, Loose Screws – 5 occurrences.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you make a Pareto Chart, this can be done in three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format the data&lt;/strong&gt; – Use a JSON, CSV, or Change node to clean or convert incoming data if needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Aggregate in a Function node&lt;/strong&gt; – Map each data point to a type (e.g., machine type, process step, defect category) and keep a running count of occurrences.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; You do not need to know JavaScript. Simply describe the desired outcome and provide a sample dataset—the &lt;strong&gt;FlowFuse Expert&lt;/strong&gt; will generate the Function node for you. &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/&quot;&gt;Learn more&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sort the results&lt;/strong&gt; – Use a Sort node to arrange categories so the most frequent appear first.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At the end of this step, your data should be transformed into a structure like this, which is the &lt;strong&gt;required format to create a Pareto Chart&lt;/strong&gt; in Step 3:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-81&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-81&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Paint Defect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Faulty Electronics&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Scratch on Surface&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Misaligned Parts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Loose Screws&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cracked Housing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-81&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-3%3A-visualizing-the-chart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#step-3%3A-visualizing-the-chart&quot;&gt;Step 3: Visualizing the Chart&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you can create a Pareto Chart visualization, ensure that you have installed the &lt;strong&gt;&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;&lt;/strong&gt; node. This library provides the essential user interface components needed to create a real-time dashboard.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Editor and click on the &lt;strong&gt;hamburger menu&lt;/strong&gt; (☰) in the top-right corner.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Install&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;&lt;/strong&gt; and click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After installation, new UI nodes—such as &lt;strong&gt;UI Chart&lt;/strong&gt;, &lt;strong&gt;UI Gauge&lt;/strong&gt;, &lt;strong&gt;UI Template&lt;/strong&gt;, and others—will appear in your palette. These nodes provide the building blocks to make a Pareto Chart and other interactive dashboard components for industrial applications.&lt;/p&gt;
&lt;p&gt;While the standard &lt;strong&gt;UI Chart&lt;/strong&gt; node supports most common chart types, it does not include a native &lt;strong&gt;Pareto chart&lt;/strong&gt;. To create a Pareto Chart with advanced features, the &lt;strong&gt;UI Template&lt;/strong&gt; node can be used, allowing you to embed custom components for fully tailored visualizations.&lt;/p&gt;
&lt;p&gt;Below is an example showing how to create a Pareto Chart using the &lt;strong&gt;UI Template&lt;/strong&gt; node. You can copy and import this flow directly into your editor to start using it immediately.&lt;/p&gt;
&lt;div id=&quot;nr-flow-245&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow245 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;fef40951758bc433&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fd8e1f4dd4a1bb0b&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;5a4c5fe0a49298d4&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Pareto Chart&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;canvas ref=&#92;&#92;&#92;&quot;chart&#92;&#92;&#92;&quot; /&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;script src=&#92;&#92;&#92;&quot;https://cdn.jsdelivr.net/npm/chart.js@4&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/script&amp;gt;&#92;&#92;n&amp;lt;script&amp;gt;&#92;&#92;n    export default {&#92;&#92;n        mounted() {&#92;&#92;n            this.draw();&#92;&#92;n            // Register a listener for incoming data from Node-RED&#92;&#92;n            this.$socket.on(&#39;msg-input:&#39; + this.id, this.onInput);&#92;&#92;n        },&#92;&#92;n        methods: {&#92;&#92;n            draw() {&#92;&#92;n                // Get the canvas element to draw the chart on&#92;&#92;n                const ctx = this.$refs.chart;&#92;&#92;n                &#92;&#92;n                // Initialize the chart with no data&#92;&#92;n                const chart = new Chart(ctx, {&#92;&#92;n                    type: &#39;bar&#39;, // This is the default type&#92;&#92;n                    data: {&#92;&#92;n                        labels: [],&#92;&#92;n                        datasets: []&#92;&#92;n                    },&#92;&#92;n                    options: {&#92;&#92;n                        responsive: true,&#92;&#92;n                        interaction: {&#92;&#92;n                            mode: &#39;index&#39;,&#92;&#92;n                            intersect: false,&#92;&#92;n                        },&#92;&#92;n                        scales: {&#92;&#92;n                            // Left Y-axis for the bars (counts)&#92;&#92;n                            y: {&#92;&#92;n                                type: &#39;linear&#39;,&#92;&#92;n                                display: true,&#92;&#92;n                                position: &#39;left&#39;,&#92;&#92;n                                title: {&#92;&#92;n                                    display: true,&#92;&#92;n                                    text: &#39;Frequency&#39;&#92;&#92;n                                },&#92;&#92;n                                beginAtZero: true&#92;&#92;n                            },&#92;&#92;n                            // Right Y-axis for the cumulative line (percentages)&#92;&#92;n                            y1: {&#92;&#92;n                                type: &#39;linear&#39;,&#92;&#92;n                                display: true,&#92;&#92;n                                position: &#39;right&#39;,&#92;&#92;n                                title: {&#92;&#92;n                                    display: true,&#92;&#92;n                                    text: &#39;Cumulative %&#39;&#92;&#92;n                                },&#92;&#92;n                                // Do not display grid lines for this axis&#92;&#92;n                                grid: {&#92;&#92;n                                    drawOnChartArea: false,&#92;&#92;n                                },&#92;&#92;n                                // Ensure the percentage scale goes to 100%&#92;&#92;n                                max: 100&#92;&#92;n                            }&#92;&#92;n                        }&#92;&#92;n                    }&#92;&#92;n                });&#92;&#92;n                &#92;&#92;n                // Make the chart object accessible to other methods&#92;&#92;n                this.chart = chart;&#92;&#92;n            },&#92;&#92;n            onInput(msg) {&#92;&#92;n                // Get the raw data from the incoming message payload&#92;&#92;n                const rawData = msg.payload;&#92;&#92;n&#92;&#92;n                let cumulativeSum = 0;&#92;&#92;n                const total = rawData.reduce((sum, item) =&amp;gt; sum + item.count, 0);&#92;&#92;n&#92;&#92;n                const labels = [];&#92;&#92;n                const barData = [];&#92;&#92;n                const lineData = [];&#92;&#92;n&#92;&#92;n                // Process the data to build chart datasets&#92;&#92;n                rawData.forEach(item =&amp;gt; {&#92;&#92;n                    labels.push(item.type);&#92;&#92;n                    barData.push(item.count);&#92;&#92;n&#92;&#92;n                    // Calculate cumulative sum and percentage&#92;&#92;n                    cumulativeSum += item.count;&#92;&#92;n                    const cumulativePercentage = (cumulativeSum / total) * 100;&#92;&#92;n                    lineData.push(cumulativePercentage);&#92;&#92;n                });&#92;&#92;n&#92;&#92;n                // Update the chart&#39;s data and labels&#92;&#92;n                this.chart.data.labels = labels;&#92;&#92;n                this.chart.data.datasets = [&#92;&#92;n                    {&#92;&#92;n                        type: &#39;bar&#39;,&#92;&#92;n                        label: &#39;Frequency&#39;,&#92;&#92;n                        data: barData,&#92;&#92;n                        backgroundColor: &#39;rgba(54, 162, 235, 0.6)&#39;,&#92;&#92;n                        yAxisID: &#39;y&#39;&#92;&#92;n                    },&#92;&#92;n                    {&#92;&#92;n                        type: &#39;line&#39;,&#92;&#92;n                        label: &#39;Cumulative Percentage&#39;,&#92;&#92;n                        data: lineData,&#92;&#92;n                        borderColor: &#39;rgb(255, 99, 132)&#39;,&#92;&#92;n                        backgroundColor: &#39;rgba(255, 99, 132, 0.4)&#39;,&#92;&#92;n                        fill: false,&#92;&#92;n                        yAxisID: &#39;y1&#39;&#92;&#92;n                    },&#92;&#92;n                    // -- START OF MODIFICATIONS --&#92;&#92;n                    {&#92;&#92;n                        type: &#39;line&#39;,&#92;&#92;n                        label: &#39;80% Threshold&#39;,&#92;&#92;n                        data: labels.map(() =&amp;gt; 80), // Creates a horizontal line at 80&#92;&#92;n                        borderColor: &#39;rgba(75, 192, 192, 1)&#39;,&#92;&#92;n                        borderWidth: 2,&#92;&#92;n                        borderDash: [5, 5], // This property creates a dotted line&#92;&#92;n                        fill: false,&#92;&#92;n                        pointRadius: 0, // Hides data points&#92;&#92;n                        yAxisID: &#39;y1&#39;&#92;&#92;n                    }&#92;&#92;n                ];&#92;&#92;n&#92;&#92;n                // Redraw the chart to show the new data&#92;&#92;n                this.chart.update();&#92;&#92;n            }&#92;&#92;n        }&#92;&#92;n    }&#92;&#92;n&amp;lt;/script&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1030,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5a4c5fe0a49298d4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Pareto Chart Group&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;74853f680cb16c6c&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;74853f680cb16c6c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;d7fb2be4d7cb92b9&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;faac104f34962f3e&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7fb2be4d7cb92b9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;faac104f34962f3e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#8ec8f3&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ebdb042b8d72fd5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.26.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow245.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-245&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;connecting-your-real-production-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#connecting-your-real-production-data&quot;&gt;Connecting Your Real Production Data&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Ensure your upstream data flow (from OPC-UA, MQTT, or database nodes) is cleaned and aggregated into the JSON format described in Step 2.&lt;/li&gt;
&lt;li&gt;Connect the output of that flow to the &lt;strong&gt;Pareto Chart (UI Template)&lt;/strong&gt; node you imported, then deploy the flow.&lt;/li&gt;
&lt;li&gt;Whenever new data arrives, the chart will automatically update, displaying both the bars (frequency) and the cumulative percentage line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To view the dashboard, click the &lt;strong&gt;Open Dashboard&lt;/strong&gt; button in the top-right corner of the Dashboard 2.0 sidebar. Your newly created Pareto Chart will appear, complete with bars, the cumulative line, and the 80% threshold.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Pareto Chart showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pareto-chart.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Pareto Chart showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The chart visualizes defect types using bars. The cumulative line and the 80% threshold indicate the cutoff point: bars to the left of this intersection represent the vital few defects that contribute most to the total—and these are the areas where you should focus your improvement efforts.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Pareto Chart showing defect categories in manufacturing. The bars on the left, highlighted with a red box, represent the vital few defects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pareto-chart-decoded.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Pareto Chart showing defect categories in manufacturing. The bars on the left, highlighted with a red box, represent the vital few defects&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#takeaways&quot;&gt;Takeaways&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By following the steps outlined above, you have successfully learned how to create a Pareto Chart that transforms raw production data into clear, actionable insights. This visualization helps manufacturing teams focus their limited time and resources on the problems that matter most.&lt;/p&gt;
&lt;h3 id=&quot;why-this-matters-for-your-business&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#why-this-matters-for-your-business&quot;&gt;Why This Matters for Your Business&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The real power when you create a Pareto Chart isn&#39;t just in identifying problems—it&#39;s in changing how your team makes decisions. Instead of trying to fix everything at once or relying on gut feelings, you now have &lt;strong&gt;data-driven clarity&lt;/strong&gt; on where to focus. This translates into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Less firefighting, more strategic improvement:&lt;/strong&gt; Teams can stop chasing every small issue and concentrate on the critical few that truly impact production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster problem resolution:&lt;/strong&gt; When everyone can see which issues dominate, alignment happens quickly and solutions get implemented faster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better conversations with management:&lt;/strong&gt; Visual data makes it easier to justify resource allocation and demonstrate the impact of improvement initiatives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous learning:&lt;/strong&gt; As the top issues are resolved, new patterns emerge, creating a cycle of ongoing improvement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;building-on-your-success&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/#building-on-your-success&quot;&gt;Building on Your Success&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With your ability to create a Pareto Chart established, you&#39;ve built a foundation for &lt;strong&gt;data-driven decision-making&lt;/strong&gt;. The same approach to make a Pareto Chart can be applied to other areas of operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Track equipment downtime reasons to optimize maintenance schedules.&lt;/li&gt;
&lt;li&gt;Analyze customer feedback to prioritize product improvements.&lt;/li&gt;
&lt;li&gt;Monitor supplier performance to strengthen the supply chain.&lt;/li&gt;
&lt;li&gt;Identify training gaps by analyzing operator errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FowFuse makes it simple to replicate this success across your organization. The same flow can be deployed to multiple lines, shared with other teams, and adapted for different use cases—while maintaining security and control through enterprise-grade features.&lt;/p&gt;
&lt;p&gt;Ready to see how FlowFuse can help your team make better decisions with production data? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; to discover how manufacturers are using visual analytics to drive continuous improvement and operational excellence.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/</id>
        <title>FlowFuse API for Industry: Automating Node-RED Instances, Devices, and CI/CD Tasks</title>
        <summary>Automate Industrial Workflows with the FlowFuse API workflows</summary>
        <updated>2025-08-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse includes an API that lets you manage Node-RED instances, edge devices, and deployments directly from your scripts or applications. While most people use the web interface, the API is a great option if you want to automate tasks or connect FlowFuse with other tools.&lt;/p&gt;
&lt;p&gt;In this guide, you’ll learn the basics of the FlowFuse API, along with practical examples you can start using right away.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-flowfuse-api-and-why-use-it%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#what-is-the-flowfuse-api-and-why-use-it%3F&quot;&gt;What is the FlowFuse API and Why Use It?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse API is a &lt;strong&gt;REST-based interface&lt;/strong&gt; fully described using the &lt;strong&gt;OpenAPI 3.0 Specification&lt;/strong&gt;, allowing you to explore its capabilities, test endpoints, and even auto-generate client libraries in multiple programming languages. It provides programmatic control over everything available in the FlowFuse platform, so instead of navigating the dashboard, you can manage Node-RED instances, devices, and deployments directly from scripts or applications.&lt;/p&gt;
&lt;p&gt;This is particularly useful when you want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manage &lt;strong&gt;multiple Node-RED instances or devices&lt;/strong&gt; simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate repetitive tasks&lt;/strong&gt; such as starting, stopping, or updating instances.&lt;/li&gt;
&lt;li&gt;Build &lt;strong&gt;custom notifications or alerts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Implement &lt;strong&gt;CI/CD pipelines&lt;/strong&gt; for testing and deploying flows automatically.&lt;/li&gt;
&lt;li&gt;Integrate FlowFuse with &lt;strong&gt;external systems&lt;/strong&gt; like monitoring, alerting, or scheduling tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, the API provides greater flexibility, simplifies automation, and allows FlowFuse to fit seamlessly into your existing workflows.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-with-the-flowfuse-api&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#getting-started-with-the-flowfuse-api&quot;&gt;Getting Started with the FlowFuse API&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you can use the API, you need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Your FlowFuse account&lt;/strong&gt;&lt;br /&gt;
You will need to authenticate using an API token, which you can generate from the FlowFuse platform.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;generating-an-api-token&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#generating-an-api-token&quot;&gt;Generating an API Token&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Log in to the FlowFuse platform.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;User Settings → Security&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Tokens&lt;/strong&gt; tab and click &lt;strong&gt;Add Token&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the form that opens:
&lt;ul&gt;
&lt;li&gt;Give the token a descriptive name (e.g., &lt;code&gt;automation-script&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;(Optional) Check &lt;strong&gt;Add Expiry Date&lt;/strong&gt; and choose a date if you want the token to automatically expire.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Token&lt;/strong&gt; to generate it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse platform token creation form showing fields for token name, expiry date, and create button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/token-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse platform token creation form showing fields for token name, expiry date, and create button.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After creation, a dialog will open showing your &lt;strong&gt;secret token&lt;/strong&gt;.&lt;br /&gt;
Click &lt;strong&gt;Copy to Clipboard&lt;/strong&gt; and store this token securely. It will only be shown once and provides full access to your account.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dialog showing the generated FlowFuse API token with copy-to-clipboard option.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/copy-token.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dialog showing the generated FlowFuse API token with copy-to-clipboard option.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;exploring-the-flowfuse-api-with-swagger&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#exploring-the-flowfuse-api-with-swagger&quot;&gt;Exploring the FlowFuse API with Swagger&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse provides &lt;strong&gt;Swagger/OpenAPI documentation&lt;/strong&gt; that gives you a complete overview of all available endpoints, along with request and response formats.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Swagger UI is &lt;strong&gt;read-only&lt;/strong&gt;. You cannot execute API calls directly from it. Its purpose is to &lt;strong&gt;display all endpoints&lt;/strong&gt; after visiting the page, so you can plan and structure your API calls in Node-RED flows, scripts, or other applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Swagger/OpenAPI documentation interface displaying endpoints for users, Node-RED instances, devices, deployments, and much more.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-swagger-api-docs.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Swagger/OpenAPI documentation interface displaying endpoints for users, Node-RED instances, devices, deployments, and much more.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;how-to-use-the-swagger-docs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#how-to-use-the-swagger-docs&quot;&gt;How to Use the Swagger Docs&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the &lt;a href=&quot;https://app.flowfuse.com/api/static/index.html&quot;&gt;FlowFuse API documentation&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once loaded, you will see &lt;strong&gt;all available endpoints&lt;/strong&gt;, organized by category:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/v1/user/&lt;/code&gt;&lt;/strong&gt; – Retrieve user details&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/v1/instances/&lt;/code&gt;&lt;/strong&gt; – List and manage Node-RED instances&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/v1/devices/&lt;/code&gt;&lt;/strong&gt; – Manage edge devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/v1/deployments/&lt;/code&gt;&lt;/strong&gt; – Trigger or monitor deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Click on each endpoint&lt;/strong&gt; to expand it and review the details, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Required parameters&lt;/li&gt;
&lt;li&gt;Headers&lt;/li&gt;
&lt;li&gt;Response schemas&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use this information to construct actual API requests in &lt;strong&gt;Node-RED HTTP Request nodes&lt;/strong&gt;, &lt;code&gt;curl&lt;/code&gt;, or other scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;making-your-first-api-call&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#making-your-first-api-call&quot;&gt;Making Your First API Call&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you have your API token, you can start interacting with the FlowFuse API. Every request must include your token in the &lt;strong&gt;Authorization&lt;/strong&gt; header.&lt;/p&gt;
&lt;h4 id=&quot;example%3A-get-user-information&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#example%3A-get-user-information&quot;&gt;Example: Get User Information&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A good first step is to fetch your user details to verify that your token works. You can use &lt;code&gt;curl&lt;/code&gt;, any HTTP client in your preferred programming language, or even do it directly within Node-RED using an &lt;strong&gt;HTTP Request&lt;/strong&gt; node, as shown below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps in Node-RED:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;HTTP Request&lt;/strong&gt; node and connect it to the Inject node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the HTTP Request node and configure it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Method: &lt;strong&gt;GET&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;URL: &lt;code&gt;https://app.flowfuse.com/api/v1/user/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Use authentication&lt;/strong&gt;, select &lt;strong&gt;Bearer Authentication&lt;/strong&gt;, and enter your API token.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect a &lt;strong&gt;Debug&lt;/strong&gt; node to the HTTP Request node to see the response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the Inject button.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When using API tokens in Node-RED flows, always store them in &lt;strong&gt;environment variables&lt;/strong&gt; instead of directly in the node to prevent accidental exposure when sharing flows. See &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;FlowFuse Environment Variables&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div id=&quot;nr-flow-239&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow239 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6fa44538b934438b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get User Details&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8c7f13373e29c907&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8c7f13373e29c907&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://app.flowfuse.com/api/v1/user/&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;bearer&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:390,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3a54169dc737b475&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3a54169dc737b475&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow239.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-239&#39;) })&lt;/script&gt;
&lt;p&gt;Once triggered, the debug panel will show your user information as shown below with status code 200, confirming that your token works and your API connection is successful.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-255&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-255&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;john.doe@example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;email_verified&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sso_enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;mfa_enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;tcs_accepted&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-01-01T00:00:00.000Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;john12345&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;johndoe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;avatar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://app.flowfuse.com/avatar/john-avatar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;createdAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-01-01T00:00:00.000Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;suspended&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-255&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;automating-devops-pipelines-with-the-flowfuse-api&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#automating-devops-pipelines-with-the-flowfuse-api&quot;&gt;Automating DevOps Pipelines with the FlowFuse API&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the most powerful features of the FlowFuse API is its ability to integrate directly with CI/CD pipelines. This makes it possible to trigger builds, deployments, or pipeline stages automatically—either from scripts or directly within Node-RED flows—reducing manual effort and accelerating development cycles.&lt;/p&gt;
&lt;p&gt;To trigger a pipeline stage, you will use the following endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PUT /api/v1/pipelines/{pipelineId}/stages/{stageId}/deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requires two pieces of information: the &lt;strong&gt;pipeline ID&lt;/strong&gt; and the &lt;strong&gt;stage ID&lt;/strong&gt;.
Before triggering a deployment, you first need to retrieve the list of pipelines for your application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /api/v1/applications/{applicationId}/pipelines
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This request returns all pipelines for the given application, including their &lt;strong&gt;pipelineId&lt;/strong&gt; and the stages associated with them. Once you identify the correct &lt;strong&gt;pipelineId&lt;/strong&gt; and &lt;strong&gt;stageId&lt;/strong&gt;, you can use them in the &lt;code&gt;deploy&lt;/code&gt; request to trigger the stage automatically.&lt;/p&gt;
&lt;h3 id=&quot;api-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#api-steps&quot;&gt;API Steps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before triggering a stage, we first need to retrieve the pipeline details for the application. This will give us both the pipeline ID and the stage ID required for deployment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Get Your Application ID&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your application in &lt;strong&gt;FlowFuse&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Settings&lt;/strong&gt; page.&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Application ID&lt;/strong&gt; (you will need this in later steps).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Retrieve Pipelines for an Application&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node to manually trigger the request.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;HTTP Request&lt;/strong&gt; node and configure it as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;GET&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;URL:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/api/v1/applications/{applicationId}/pipelines
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;{applicationId}&lt;/code&gt; with the actual Application ID you copied in Step 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt; Enable &lt;strong&gt;Bearer Authentication&lt;/strong&gt; and set it to use your API token from the environment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;Inject&lt;/strong&gt; node to the &lt;strong&gt;HTTP Request&lt;/strong&gt; node, and then connect the &lt;strong&gt;HTTP Request&lt;/strong&gt; node to a &lt;strong&gt;Debug&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the Inject button to retrieve the pipelines.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;The response will return a list of pipelines, each containing a unique &lt;strong&gt;pipelineId&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-240&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow240 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;7ad2c2d998c60b39&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Pipelines&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dda168427fc847df&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dda168427fc847df&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://app.flowfuse.com/api/v1/applications/{applicationID}/pipelines&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;bearer&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4a8c8520e2d33e37&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4a8c8520e2d33e37&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5027784675bcf4ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow240.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-240&#39;) })&lt;/script&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Identify the Stage&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the pipeline details returned from Step 2.&lt;/li&gt;
&lt;li&gt;Note the &lt;strong&gt;pipelineId&lt;/strong&gt; and the &lt;strong&gt;stageId&lt;/strong&gt; of the stage you want to trigger.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Trigger the Stage Deployment&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once you have the &lt;code&gt;pipelineId&lt;/code&gt; and &lt;code&gt;stageId&lt;/code&gt;, you can trigger the deployment stage with a &lt;code&gt;PUT&lt;/code&gt; request.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add another &lt;strong&gt;Inject&lt;/strong&gt; node to trigger the deployment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect it to a new &lt;strong&gt;HTTP Request&lt;/strong&gt; node and configure it as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;PUT&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;URL:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/api/v1/pipelines/{pipelineId}/stages/{stageId}/deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;{pipelineId}&lt;/code&gt; and &lt;code&gt;{stageId}&lt;/code&gt; with the values from Step 3.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt; Use &lt;strong&gt;Bearer Authentication&lt;/strong&gt; with your API token.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the HTTP Request node to a &lt;strong&gt;Debug&lt;/strong&gt; node to view the response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click Inject.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If successful, you will receive a JSON response confirming that the deployment stage has been triggered.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-416&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-416&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;importing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-416&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The FlowFuse API allows you to deploy a specific stage of a pipeline. It does not automatically move to the next stage, but you can create a workflow that monitors the status of each stage and triggers the next one once the current stage is complete.
In the following flow, the development stage is deployed every day at 10 PM. After that, the workflow checks the status of the next stage, the staging instance, before proceeding.&lt;/p&gt;
&lt;div id=&quot;nr-flow-241&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow241 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;1ab940eb2ef10760&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Deploy Development Stage&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;PUT&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://app.flowfuse.com/api/v1/pipelines/{pipelineId}/stages/{stageId}/deploy&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;bearer&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1c13b0d508913f6d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;293221e2fafef9ff&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Check Staging Instance Status&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://app.flowfuse.com/api/v1/projects/${instanceId}/status&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;bearer&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;24192bf21e52edd2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6f94bfb0d3198597&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Deploy Staging Stage&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;PUT&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://app.flowfuse.com/api/v1/pipelines/{pipelineId}/stages/{stageId}/deploy&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;bearer&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b267c3b0ecbbf0bd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;24192bf21e52edd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Is Running?&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload.meta.state&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;running&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f94bfb0d3198597&#92;&quot;,&#92;&quot;9cf7ccb7e740b39e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7ace2bed48a14cda&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger Pipeline&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;00 22 * * *&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1ab940eb2ef10760&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b267c3b0ecbbf0bd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c13b0d508913f6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Wait for Stage Complete&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Clear any existing interval or timeout from context&#92;&#92;nlet existingInterval = context.get(&#92;&#92;&#92;&quot;intervalId&#92;&#92;&#92;&quot;);&#92;&#92;nlet existingTimeout = context.get(&#92;&#92;&#92;&quot;timeoutId&#92;&#92;&#92;&quot;);&#92;&#92;n&#92;&#92;nif (existingInterval) {&#92;&#92;n    clearInterval(existingInterval);&#92;&#92;n    context.set(&#92;&#92;&#92;&quot;intervalId&#92;&#92;&#92;&quot;, null);&#92;&#92;n}&#92;&#92;nif (existingTimeout) {&#92;&#92;n    clearTimeout(existingTimeout);&#92;&#92;n    context.set(&#92;&#92;&#92;&quot;timeoutId&#92;&#92;&#92;&quot;, null);&#92;&#92;n}&#92;&#92;n&#92;&#92;n// If state = &#92;&#92;&#92;&quot;running&#92;&#92;&#92;&quot;, stop polling completely&#92;&#92;nif (msg.payload?.meta?.state === &#92;&#92;&#92;&quot;running&#92;&#92;&#92;&quot;) {&#92;&#92;n    node.status({ fill: &#92;&#92;&#92;&quot;green&#92;&#92;&#92;&quot;, shape: &#92;&#92;&#92;&quot;dot&#92;&#92;&#92;&quot;, text: &#92;&#92;&#92;&quot;Stage running&#92;&#92;&#92;&quot; });&#92;&#92;n    return null; // stop completely&#92;&#92;n}&#92;&#92;n&#92;&#92;n//  send the first message immediately&#92;&#92;nnode.send(RED.util.cloneMessage(msg));&#92;&#92;n&#92;&#92;n// Start polling interval (send msg every 2 seconds)&#92;&#92;nlet id = setInterval(() =&amp;gt; {&#92;&#92;n    node.send(RED.util.cloneMessage(msg)); // clone msg to avoid side effects&#92;&#92;n}, 2000);&#92;&#92;n&#92;&#92;n// Auto-clear interval after 60 seconds to avoid leaks&#92;&#92;nlet timeoutId = setTimeout(() =&amp;gt; {&#92;&#92;n    clearInterval(id);&#92;&#92;n    context.set(&#92;&#92;&#92;&quot;intervalId&#92;&#92;&#92;&quot;, null);&#92;&#92;n    context.set(&#92;&#92;&#92;&quot;timeoutId&#92;&#92;&#92;&quot;, null);&#92;&#92;n    node.status({ fill: &#92;&#92;&#92;&quot;red&#92;&#92;&#92;&quot;, shape: &#92;&#92;&#92;&quot;dot&#92;&#92;&#92;&quot;, text: &#92;&#92;&#92;&quot;Polling stopped (timeout)&#92;&#92;&#92;&quot; });&#92;&#92;n}, 60000);&#92;&#92;n&#92;&#92;n// Save interval and timeout IDs in context&#92;&#92;ncontext.set(&#92;&#92;&#92;&quot;intervalId&#92;&#92;&#92;&quot;, id);&#92;&#92;ncontext.set(&#92;&#92;&#92;&quot;timeoutId&#92;&#92;&#92;&quot;, timeoutId);&#92;&#92;n&#92;&#92;n// Update node status to indicate polling is active&#92;&#92;nnode.status({ fill: &#92;&#92;&#92;&quot;yellow&#92;&#92;&#92;&quot;, shape: &#92;&#92;&#92;&quot;ring&#92;&#92;&#92;&quot;, text: &#92;&#92;&#92;&quot;Polling...&#92;&#92;&#92;&quot; });&#92;&#92;n&#92;&#92;n// Do not return any message immediately (already sent above)&#92;&#92;nreturn null;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;293221e2fafef9ff&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9cf7ccb7e740b39e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;a58e64a12df0c55e&#92;&quot;],&#92;&quot;x&#92;&quot;:725,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a58e64a12df0c55e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;37326e20f2cf9fc5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 1&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;9cf7ccb7e740b39e&#92;&quot;],&#92;&quot;x&#92;&quot;:255,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1c13b0d508913f6d&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow241.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-241&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-node-red-api/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse API puts you in control of your Node-RED infrastructure through code. Instead of managing instances manually, you can automate repetitive tasks, integrate with existing tools, and build custom workflows that fit your exact needs.&lt;/p&gt;
&lt;p&gt;Whether you&#39;re managing a handful of instances or thousands of edge devices, the API scales with you. It&#39;s straightforward to get started—generate a token, make your first API call, and gradually automate more of your workflow as you go.&lt;/p&gt;
&lt;p&gt;The real value comes from the time you save and the consistency you gain. Let the API handle the routine work while you focus on building great Node-RED applications.&lt;/p&gt;
&lt;p&gt;Start today by generating your first API token and making a call — you’ll see how quickly FlowFuse can automate your Node-RED operations. &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Sign up for free&lt;/a&gt; and put your industrial workflows on autopilot.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/</id>
        <title>Pareto Chart &amp; Diagram: What It Is, Formula, Examples &amp; Manufacturing Applications</title>
        <summary>How the Pareto principle helps manufacturing teams focus where it matters most.</summary>
        <updated>2025-08-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A Pareto Chart helps manufacturing teams cut through the chaos when problems arrive in clusters—defects, delays, downtime, and customer complaints all competing for attention. With limited resources and time, how do you decide which fire to put out first?&lt;/p&gt;
&lt;p&gt;A Pareto Chart is a decision-making tool that reveals which problems deserve immediate attention and which can wait. Based on the principle that roughly 80% of problems stem from 20% of causes, this visual tool transforms chaos into clarity. It shows manufacturing teams exactly where to focus their efforts for maximum impact.&lt;/p&gt;
&lt;p&gt;Whether you call it a Pareto Chart, Pareto diagram, or Pareto analysis graph, this quality control tool serves the same purpose: helping you identify and prioritize the most impactful problems in your manufacturing process.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-pareto-principle-%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#what-is-the-pareto-principle-%3F&quot;&gt;What is the Pareto Principle ?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Pareto Principle, discovered by Italian economist Vilfredo Pareto in 1896, reveals a universal truth: imbalance is the norm, not the exception. Pareto originally observed that 80% of Italy&#39;s land belonged to 20% of the population. This same pattern appears everywhere in manufacturing.&lt;/p&gt;
&lt;p&gt;Think about your own facility. Chances are, most of your headaches come from a handful of root causes. A few machines cause most breakdowns. A small number of suppliers create most delays. A limited set of defect types generate most customer complaints. The Pareto Chart makes these hidden patterns visible, turning intuition into actionable data.&lt;/p&gt;
&lt;p&gt;If you prefer video, watch this quick explainer to understand the Pareto Principle:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;lsGwqk_agcQ&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;pareto-chart-vs-pareto-diagram%3A-what&#39;s-the-difference%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#pareto-chart-vs-pareto-diagram%3A-what&#39;s-the-difference%3F&quot;&gt;Pareto Chart vs Pareto Diagram: What&#39;s the Difference?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;ll hear both terms used interchangeably in manufacturing—and they refer to the same tool. &amp;quot;Pareto Chart&amp;quot; is more common in North America, while &amp;quot;Pareto diagram&amp;quot; is frequently used in ISO standards and international quality documentation. Whether your team calls it a chart, diagram, or graph, the visualization combines bar charts with a cumulative line to reveal the vital few causes driving the majority of your problems.&lt;/p&gt;
&lt;h3 id=&quot;pareto-chart-formula&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#pareto-chart-formula&quot;&gt;Pareto Chart Formula&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Creating a Pareto diagram involves a straightforward calculation process. Here&#39;s the step-by-step formula approach:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Calculate Frequency or Impact&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First, count how many times each problem occurs (or calculate the cost/impact of each problem type).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Frequency = Number of occurrences for each category
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Calculate Total&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add up all frequencies to get the total:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Total = Sum of all frequencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Calculate Individual Percentage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For each category, calculate what percentage it represents of the total:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Individual Percentage = (Category Frequency / Total) × 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Calculate Cumulative Percentage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Starting from the largest category, add percentages progressively:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cumulative Percentage = Sum of all previous percentages + Current percentage
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-does-a-pareto-chart-show%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#what-does-a-pareto-chart-show%3F&quot;&gt;What Does a Pareto Chart Show?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Pareto diagram combines the best of both worlds—the immediate clarity of a bar graph with the cumulative insight of a line graph. Here&#39;s what makes it powerful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Bars Tell the Story&lt;/strong&gt;: Each vertical bar represents a problem category, arranged from tallest to shortest. The height shows frequency or impact. This simple arrangement immediately draws your eye to the biggest problems—no statistical knowledge required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Line Shows the Opportunity&lt;/strong&gt;: The cumulative percentage line climbs from left to right, showing the combined impact of addressing each problem. When this line starts to flatten, you&#39;ve found your &amp;quot;vital few&amp;quot;—the problems that, once solved, will transform your operation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Axes Frame the Decision&lt;/strong&gt;: The left axis measures actual occurrences, the right shows cumulative percentage, and the horizontal axis lists your problem categories. Together, they create a complete picture that anyone can understand and act upon.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This visualization does something remarkable: it makes the invisible visible. Problems that seemed equally important suddenly reveal their true impact. The path forward becomes clear.&lt;/p&gt;
&lt;h2 id=&quot;pareto-real-world-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#pareto-real-world-example&quot;&gt;Pareto Real World Example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Pareto diagram showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pareto-chart-image.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Pareto diagram showing defect categories in manufacturing with bars for scratches, cracks, color issues, and other defects, alongside a cumulative percentage line.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Look at this real Pareto diagram from a manufacturing facility. The bars show different types of defects found in one month, arranged from most common (scratches) to least common (other defects).&lt;/p&gt;
&lt;p&gt;Here&#39;s the key insight: See where the orange line crosses the 80% mark? It happens after just three defect types—scratches, cracks, and color issues. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix these three problems → Eliminate 80% of all defects&lt;/li&gt;
&lt;li&gt;Ignore the other six for now → Save time and resources&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead of trying to fix nine different problems, the team focuses on just three:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Why do scratches happen? (Maybe rough handling)&lt;/li&gt;
&lt;li&gt;What causes cracks? (Could be temperature changes)&lt;/li&gt;
&lt;li&gt;How to fix color issues? (Check supplier materials)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This simple focus typically cuts total defects by 60-70% in just a few months. That&#39;s the power of Pareto—work smarter, not harder.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-pareto-chart-(diagram)-used-for-%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#what-is-a-pareto-chart-(diagram)-used-for-%3F&quot;&gt;What is a Pareto chart (diagram) used for ?&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Quality Control&lt;/strong&gt;
Smart manufacturers prioritize defects, not just track them. When teams break down defects into specific categories—particle contamination, dimensional variations, assembly errors, material flaws—each reveals different root causes requiring targeted solutions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key is specificity. Generic &amp;quot;defect&amp;quot; tracking will not reveal actionable insights. Break them down into meaningful categories that point to specific improvement opportunities.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Equipment Maintenance&lt;/strong&gt;
Traditional maintenance schedules treat all equipment equally, but Pareto analysis reveals this approach wastes resources. Manufacturing studies show that bearing wear and sensor failures often account for nearly 50% of all equipment failure occurrences. By identifying which specific components cause the most downtime, teams can shift from time-based maintenance to condition monitoring on critical equipment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The lesson: focus your predictive maintenance budget where failures hurt most.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Supply Chain Intelligence&lt;/strong&gt;
When supplier issues multiply, Pareto diagrams cut through the noise. Manufacturing teams tracking supplier-caused delays often discover that a small fraction of suppliers cause the majority of production stoppages. This data-driven insight enables targeted negotiations for backup agreements and buffer stock arrangements with critical suppliers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Safety Management&lt;/strong&gt;
Safety teams using Pareto analysis on incident data typically find that specific operations or areas account for the majority of lost-time incidents. This focused view enables targeted ergonomic improvements and specialized training where they will prevent the most harm.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Safety resources are precious. Pareto diagrams ensure they go where they will have maximum impact.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;strong&gt;Cost Reduction&lt;/strong&gt;
Not all problems cost the same. Frequency alone can mislead—a defect occurring frequently but costing little to fix might be less important than rare defects causing expensive customer line stops. Cost-weighted Pareto Charts often completely reverse improvement priorities, focusing teams on high-impact issues rather than high-frequency ones.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;why-pareto-charts-matter-now-more-than-ever&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#why-pareto-charts-matter-now-more-than-ever&quot;&gt;Why Pareto Charts Matter Now More Than Ever&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturing is more complex than ever. Global supply chains, tight margins, and higher quality expectations mean every decision and every resource matters. Pareto charts help teams focus on what truly drives problems and results.&lt;/p&gt;
&lt;p&gt;One major benefit is speed of decision-making. In manufacturing, slow decisions cost money. A Pareto chart reduces analysis time from days to minutes. With a quick look, teams can see which issues matter most and where action is needed.&lt;/p&gt;
&lt;p&gt;Another advantage is that Pareto charts are easy to understand. Operators, engineers, and executives can all read the same chart and reach the same conclusion. This shared understanding improves alignment and speeds up action without requiring deep statistical knowledge.&lt;/p&gt;
&lt;p&gt;Pareto charts also make progress visible. When charts are updated regularly, it becomes clear whether improvements are working. When the largest bars shrink or rankings change, teams can see real results instead of relying on assumptions.&lt;/p&gt;
&lt;p&gt;Beyond solving daily problems, Pareto charts support long-term strategy. Repeated patterns across multiple charts can reveal deeper issues. If supplier-related problems appear at the top again and again, it may signal the need to rethink sourcing. If equipment failures dominate, investment in maintenance, upgrades, or automation may be justified.&lt;/p&gt;
&lt;p&gt;Organizations that track Pareto trends over time can also prevent future problems. When a small issue starts moving up the chart month after month, teams can investigate early and address it before it becomes a major disruption.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/pareto-chart-manufacturing-guide/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In manufacturing, success isn&#39;t about solving every problem—it&#39;s about solving the right problems first. Pareto Charts cut through the noise to show you exactly where your efforts will deliver the greatest returns. By focusing on the vital few causes that drive the majority of your issues, you transform scattered firefighting into strategic improvement.&lt;/p&gt;
&lt;p&gt;The beauty of Pareto analysis lies in its simplicity. No complex formulas, no statistical expertise required—just clear visual evidence that guides your team toward impact. Whether you&#39;re reducing defects, minimizing downtime, or cutting costs, the Pareto principle remains your compass: tackle the 20% that matters, and watch 80% of your problems disappear.&lt;/p&gt;
&lt;p&gt;But knowing the principle and applying it in real-time are two different challenges. Modern manufacturing moves fast, and static charts built from monthly data reports can&#39;t keep pace. &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; bridges this gap by connecting directly to your production systems, automatically collecting data, and generating dynamic Pareto diagrams that evolve as your operation does. See problems emerge before they escalate. Track improvements as they happen. Make decisions backed by live data, not outdated reports.&lt;/p&gt;
&lt;p&gt;The first step is always the hardest—and the most important. Choose one persistent problem area this week. Gather the data. Build your first Pareto Chart. You&#39;ll be surprised how quickly priorities become obvious and how fast your team aligns around them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Next up:&lt;/strong&gt; read our article on &lt;a href=&quot;https://flowfuse.com/blog/2025/09/creating-pareto-chart/&quot;&gt;building interactive Pareto diagrams in FlowFuse&lt;/a&gt; that connect directly to your production systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ready to transform your manufacturing data into actionable insights?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Stop guessing which problems to tackle first. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse free for 14 days&lt;/a&gt; and build automated Pareto Charts that connect directly to your production data, or &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;see a live demo&lt;/a&gt; of how leading manufacturers identify their vital few problems in real-time.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/</id>
        <title>FlowFuse 2.21: AI-Assisted SQL, Low-Code Custom Nodes, and Remote Instance Performance Insights</title>
        <summary>Introducing FlowFuse Expert functionality in Tables to do natural language queries of your databases, Remote Instance observability to improve performance monitoring, Team Broker nodes to make MQTT even easier to work with, a new Energy Monitoring Blueprint, Annual Billing for Self-Service, AI-Generated Snapshot Summaries, and new subflow version control to provide low-code development of custom nodes.</summary>
        <updated>2025-08-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It&#39;s been a very busy release and we have many great new features available on FlowFuse that will provide a better Node-RED development experience, makes it easier to develop and interface with your Unified Namespace, provide more insight into Remote Instance performance and new low-code tooling for building your own custom Node-RED nodes.&lt;/p&gt;
&lt;h2 id=&quot;assistant-functionality-in-tables-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#assistant-functionality-in-tables-nodes&quot;&gt;Assistant Functionality in Tables Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Gif showing FlowFuse Expert in Tables&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert in Tables recognizes table schema and turns natural language prompts into SQL queries&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Building on our successful &lt;a href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/&quot;&gt;Tables launch in 2.20&lt;/a&gt;, we&#39;ve now integrated AI assistance directly into our Tables nodes. This lowers the barrier for working with databases, reducing the dependency on SQL knowledge. With this, you can type a natural language prompt that will be interpreted in light of the structure of tables in your FlowFuse Tables, which enables an AI-supported autocomplete and assists with writing SQL specifically for connected FlowFuse tables.&lt;/p&gt;
&lt;p&gt;This integration makes working with FlowFuse Tables even more accessible, allowing developers to leverage AI guidance for database operations without requiring deep SQL expertise.&lt;/p&gt;
&lt;h2 id=&quot;summarize-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#summarize-snapshots&quot;&gt;Summarize Snapshots&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing snapshot summarization feature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;New snapshot summarization provides clear, AI-generated descriptions of changes between versions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Managing instance versions becomes more intuitive with our new Snapshot Summary feature. When creating snapshots, FlowFuse can now automatically generate intelligent summaries that describes the changes introduced. This saves you time, and makes it much easier for teams to understand project evolution and quickly identify the right version for deployment or rollback scenarios.&lt;/p&gt;
&lt;p&gt;Available for Pro and Enterprise.&lt;/p&gt;
&lt;h2 id=&quot;team-broker-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#team-broker-nodes&quot;&gt;Team Broker Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Easily publish and subscribe to topics in the FlowFuse Broker using new Team Broker nodes. Send a message from a Node-RED flow directly into the FlowFuse Broker. These new nodes extend the Unified Namespace capabilities of FlowFuse and provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Publish Node&lt;/strong&gt;: Send messages to any topic on your team broker with configurable retention settings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscribe Node&lt;/strong&gt;: Receive messages from specified topics with flexible output formatting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-Configuration&lt;/strong&gt;: Nodes automatically use your team&#39;s broker settings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypedInput Support&lt;/strong&gt;: Dynamic topic configuration using message properties or static values&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These nodes make working between Node-RED and the FlowFuse Broker much simpler and easier.&lt;/p&gt;
&lt;h2 id=&quot;low-code-custom-node-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#low-code-custom-node-development&quot;&gt;Low-Code Custom Node Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nodered.org/docs/user-guide/editor/workspace/subflows&quot;&gt;Subflows&lt;/a&gt; are a great way in Node-RED to build custom nodes, all within the Node-RED Editor, and without having to write any code. The limitation of Subflows though is that they&#39;re constrained to just one Instance of Node-RED, they cannot be shared across your whole team. That is no longer the case.&lt;/p&gt;
&lt;p&gt;We&#39;ve now introduced the Subflow exporter which provides a low-code and intuitive way to create and manage custom nodes.&lt;/p&gt;
&lt;p&gt;From the sidebar in your Node-RED Editor, you can now very easily create and manage custom nodes, without writing code or having to create and manage your own version control infrastructure. Simply create a flow in Node-RED, convert it to a subflow, fill out the package details for your new custom node and hit &amp;quot;Publish&amp;quot;. Now your new node is available for all to install across your FlowFuse team.&lt;/p&gt;
&lt;p&gt;Available for Enterprise customers only.&lt;/p&gt;
&lt;h2 id=&quot;remote-instance-observability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#remote-instance-observability&quot;&gt;Remote Instance Observability&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of remote instance monitoring interface&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/remote.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Remote Instance monitoring in the Performance view provides usage insights&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Following the success of our &lt;a href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#enhanced-observability-for-better-performance-management&quot;&gt;Hosted Instance performance monitoring&lt;/a&gt;, we&#39;ve extended observability capabilities to include Remote Instances too. This extension gives insight into CPU usage and memory usage for your remote instances.&lt;/p&gt;
&lt;p&gt;This enhancement is particularly valuable for industrial deployments where remote instances run critical processes across multiple locations.&lt;/p&gt;
&lt;h2 id=&quot;blueprint%3A-energy-monitoring-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#blueprint%3A-energy-monitoring-dashboard&quot;&gt;Blueprint: Energy Monitoring Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of energy monitoring dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/energy-monitoring.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Energy Monitoring Dashboard provides realtime usage and cost insights&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This Blueprint provides a real-time energy monitoring dashboard template for industrial facilities. It features live consumption tracking, cost analytics, spike detection, and historical trending with an integrated energy rate display. Perfect for demonstrating IoT energy management capabilities, and with Node-RED, it is fully customizable.&lt;/p&gt;
&lt;h2 id=&quot;annual-billing-option&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#annual-billing-option&quot;&gt;Annual Billing Option&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of annual billing selection interface&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/annual-billing.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;New annual billing options provide cost savings and simplified budget planning&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse Cloud customers on Starter and Pro plans can now choose to subscribe on a yearly basis and receive a free month for doing so. This allows teams to save money compared to a monthly subscription and lock in current pricing.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the next release, we&#39;re working on features that will enable you to connect your own AI models with Node-RED and FlowFuse, paving the way to create AI-supported automations in your applications.  We&#39;re also planning on pushing a lot of performance updates to Dashboard, and to make it even easier to build your own applications on FlowFuse. We&#39;re excited about it -- stay tuned!&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.21 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.21.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-release-2-21/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/</id>
        <title>Orchestrating Virtual Power Plants: How Low-Code Platforms Bridge the Gap</title>
        <summary>Why low-code tools are the missing link in scaling distributed energy systems</summary>
        <updated>2025-08-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Our electric grid is changing. For a century, it operated as a one-way street: large, centralized power plants generated electricity and pushed it downstream to homes and businesses. But today, that model is shifting. Rooftop solar panels, home batteries, and electric vehicles (EVs) are turning that one-way street into a dynamic, two-way intersection.&lt;/p&gt;
&lt;p&gt;These technologies are known as &lt;strong&gt;Distributed Energy Resources (DERs)&lt;/strong&gt;. They promise a cleaner, more resilient, and more flexible energy future. However, with that promise comes a challenge: how do we manage this growing web of distributed systems? How do we coordinate them to work seamlessly with the traditional grid? The answer lies in the concept of the &lt;strong&gt;Virtual Power Plant (VPP).&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-virtual-power-plant%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/#what-is-a-virtual-power-plant%3F&quot;&gt;What is a Virtual Power Plant?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Virtual Power Plant isn’t a physical facility. It’s a &lt;strong&gt;software-based system&lt;/strong&gt; that connects and orchestrates hundreds — sometimes thousands — of DERs into a unified energy asset. Think of it like a conductor of an orchestra: the conductor doesn’t play an instrument, but ensures that every musician plays at the right time and in harmony with the others.&lt;/p&gt;
&lt;p&gt;Similarly, a VPP ensures that solar panels, batteries, EVs, and other devices respond to real-time energy conditions. It might tell a group of batteries to store excess solar power during the afternoon or instruct EVs to send power back to the grid during a peak evening demand spike. The goal is coordinated action that supports both local needs and broader grid stability.&lt;/p&gt;
&lt;h2 id=&quot;why-vpps-have-been-so-hard-to-build&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/#why-vpps-have-been-so-hard-to-build&quot;&gt;Why VPPs Have Been So Hard to Build&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the concept of a VPP is not new, the execution has long been a technical and operational struggle. At the heart of the problem is &lt;strong&gt;integration&lt;/strong&gt; — getting disparate devices and systems to work together.&lt;/p&gt;
&lt;p&gt;First, there&#39;s the &lt;strong&gt;vendor lock-in problem&lt;/strong&gt;. You might buy a top-tier battery system, only to find it doesn&#39;t communicate with your solar inverter from another manufacturer. This limits functionality and undermines the value of your investment.&lt;/p&gt;
&lt;p&gt;Second, there&#39;s the &lt;strong&gt;manual integration nightmare&lt;/strong&gt;. Engineers often spend weeks writing custom code to onboard new devices — and they must do this over and over for each new asset. It’s time-consuming, expensive, and frustrating.&lt;/p&gt;
&lt;p&gt;Third, the data you eventually collect typically comes in &lt;strong&gt;inconsistent formats&lt;/strong&gt;, making it difficult to use without first cleaning and transforming it. Valuable time is lost in standardizing data before any control logic can be applied.&lt;/p&gt;
&lt;p&gt;Finally, there&#39;s the &lt;strong&gt;challenge of scale&lt;/strong&gt;. As the number and types of assets grow, so do the operational complexities. How do you securely update logic across thousands of devices? How do you ensure uptime and reliability? How do you onboard new assets without starting from scratch every time? Without a centralized management platform, these challenges quickly become overwhelming.&lt;/p&gt;
&lt;h2 id=&quot;low-code%3A-the-universal-translator-for-the-grid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/#low-code%3A-the-universal-translator-for-the-grid&quot;&gt;Low-Code: The Universal Translator for the Grid&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where &lt;strong&gt;low-code platforms&lt;/strong&gt;, like &lt;strong&gt;FlowFuse&lt;/strong&gt; built on &lt;strong&gt;Node-RED&lt;/strong&gt;, come into play. They offer a powerful and accessible way to bridge the technical gap — without reinventing the wheel every time.&lt;/p&gt;
&lt;p&gt;Using a low-code platform, an engineer can visually build flows and logic without needing to write large amounts of custom code. This approach dramatically accelerates development and reduces complexity.&lt;/p&gt;
&lt;p&gt;For example, connecting to devices becomes as simple as dragging and dropping pre-built nodes. You can pull data from a solar panel using Modbus, a battery using a REST API, and even fetch weather forecasts — all within the same interface.&lt;/p&gt;
&lt;p&gt;Once the data is collected, standardizing it is straightforward. JSON, CSV, Change, and function nodes allow you to reformat disparate data streams into a single, consistent structure that the VPP can understand.&lt;/p&gt;
&lt;p&gt;Building logic is also visual. You can create rules like:
&lt;strong&gt;“If the electricity price is high and the batteries are full, then send power to the grid.”&lt;/strong&gt;
Such logic is easy to build, read, and modify — even for teams that aren&#39;t deeply technical.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-scaling-and-securing-the-vpp&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/#flowfuse%3A-scaling-and-securing-the-vpp&quot;&gt;FlowFuse: Scaling and Securing the VPP&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond integration, &lt;strong&gt;FlowFuse&lt;/strong&gt; provides the centralized control and management layer that VPPs need to scale. It gives operators a &lt;strong&gt;single dashboard&lt;/strong&gt; to deploy logic, monitor device health, and push updates — regardless of how large or geographically dispersed the device fleet is.&lt;/p&gt;
&lt;p&gt;Need to onboard new assets? You can do it from the same platform, without custom scripts or separate tools. This is what makes it possible to scale from managing &lt;strong&gt;100 devices to 10,000&lt;/strong&gt; — in a structured, reliable way.&lt;/p&gt;
&lt;p&gt;FlowFuse is also designed with &lt;strong&gt;industrial-grade security&lt;/strong&gt; and management capabilities, essential for critical infrastructure environments. Role-based access control, audit logs, and deployment workflows are all built in.&lt;/p&gt;
&lt;p&gt;And importantly, FlowFuse supports &lt;strong&gt;collaborative development&lt;/strong&gt;. No more siloed knowledge stuck with one engineer. Teams can work together in a controlled environment, making development faster and more sustainable.&lt;/p&gt;
&lt;h2 id=&quot;ready-to-build-smarter-energy-systems%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/orchestrating-virtual-power-plants-low-code-platforms/#ready-to-build-smarter-energy-systems%3F&quot;&gt;Ready to Build Smarter Energy Systems?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Virtual Power Plants are the future of the energy grid — but building them without the right tools is slow, brittle, and expensive. Low-code platforms like &lt;strong&gt;FlowFuse&lt;/strong&gt; change that. They offer a practical, scalable, and secure way to integrate DERs, manage fleet operations, and coordinate distributed energy like never before.&lt;/p&gt;
&lt;p&gt;Ready to revolutionize your energy infrastructure? Start building your VPP with &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;FlowFuse&#39;s free trial&lt;/a&gt; or &lt;a href=&quot;https://meetings-eu1.hubspot.com/michael-davis/round-robin-michael-omar-kasheef?utm_campa%5B%E2%80%A6%5D113138546=&amp;amp;utm_content=113138546&amp;amp;utm_source=hs_automation&amp;amp;uuid=67e4a958-c21e-4463-8eb4-647cc2386930&quot;&gt;Book a Demo&lt;/a&gt; to see how leading energy companies are orchestrating thousands of DERs with low-code automation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/annual_billing/</id>
        <title>Save with FlowFuse Annual Billing – Now Available!</title>
        <summary>Get one month free when you pay annually</summary>
        <updated>2025-08-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/annual_billing/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;We&#39;re excited to announce that FlowFuse customers can now choose annual billing for their Starter and Pro plans! Starting today, when you choose to pay for a full year upfront, you&#39;ll get one month completely free.&lt;/p&gt;
&lt;h2 id=&quot;how-annual-billing-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/annual_billing/#how-annual-billing-works&quot;&gt;How Annual Billing Works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Switching to annual billing is straightforward:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;New customers:&lt;/strong&gt; Select annual billing when signing up for Starter or Pro plans&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Existing customers:&lt;/strong&gt; To switch to annual billing, go to &lt;strong&gt;Billing&lt;/strong&gt; → &lt;strong&gt;Upgrade Team&lt;/strong&gt;. Enable the yearly billing toggle, then click Switch to Yearly Billing.&lt;/p&gt;
&lt;p&gt;When you switch to annual billing, any unused time from your current bill will be applied as a credit on your new invoice. For example, if you paid for a month and you upgrade to annual billing halfway through the month, that remaining half of a month charge will be deducted from your next invoice.&lt;/p&gt;
&lt;p&gt;As your applications grow with additional Node-RED instances, you may wonder what happens if you add or delete instances. Not a problem: additional instances beyond the basic allowance for your plan - one hosted instance for Starter, five instances for Pro - will be billed yearly as well, but if you remove instances the amount you have already paid will be prorated either toward the next yearly billing cycle or toward any new product subscriptions you add, whichever comes first.&lt;/p&gt;
&lt;p&gt;Your annual subscription will automatically renew each year unless you choose to cancel, giving you continuous access to FlowFuse&#39;s comprehensive Node-RED hosting and development platform.&lt;/p&gt;
&lt;h2 id=&quot;why-choose-annual-billing%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/annual_billing/#why-choose-annual-billing%3F&quot;&gt;Why Choose Annual Billing?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond the immediate cost savings, annual billing offers several advantages for teams and individual developers:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Financial Benefits:&lt;/strong&gt; Lock in current pricing for a full year and save money that can be invested back into your projects and development initiatives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Administrative Simplicity:&lt;/strong&gt; Reduce the overhead of monthly billing cycles and invoice processing, especially valuable for teams managing multiple subscriptions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-term Planning:&lt;/strong&gt; Annual commitments align well with project planning cycles and budget allocation, making it easier to plan your Node-RED development roadmap.&lt;/p&gt;
&lt;h2 id=&quot;perfect-for-growing-teams&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/annual_billing/#perfect-for-growing-teams&quot;&gt;Perfect for Growing Teams&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whether you&#39;re a solo developer working on IoT projects or part of a larger team building enterprise automation solutions, annual billing provides the stability and savings that support sustained growth and development.&lt;/p&gt;
&lt;p&gt;Our Starter plan remains perfect for individual developers and small projects, while the Pro plan continues to offer the advanced features and scalability that growing teams need.&lt;/p&gt;
&lt;h2 id=&quot;get-started-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/annual_billing/#get-started-today&quot;&gt;Get Started Today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ready to start saving with annual billing? Log into your FlowFuse account to make the switch, or sign up for a new annual plan today.&lt;/p&gt;
&lt;p&gt;Questions about annual billing or need help choosing the right plan? Our support team is ready to help.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse free →&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/</id>
        <title>Building Historical Data Dashboard with FlowFuse Tables</title>
        <summary>Collect, transform, store and visualize IIoT data using FlowFuse Tables</summary>
        <updated>2025-08-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In Industrial IoT, tracking data over time is crucial. Whether you’re monitoring temperature changes throughout the day, spotting machine downtime, or analyzing production trends across shifts, a historical data dashboard helps you see important patterns clearly.&lt;/p&gt;
&lt;p&gt;This tutorial guides you through building such a dashboard using FlowFuse Tables. FlowFuse Tables currently provides a managed PostgreSQL database—a reliable and widely used system—which we will use throughout this tutorial to store time-series data.&lt;/p&gt;
&lt;h2 id=&quot;why-postgresql-for-time-series-data%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#why-postgresql-for-time-series-data%3F&quot;&gt;Why PostgreSQL for Time-Series Data?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You might wonder if PostgreSQL can efficiently handle large volumes of time-series data. The answer is yes—when configured properly. Without optimization, query performance can slow as data grows. However, by using techniques like batch inserts and smart indexing, PostgreSQL delivers fast and reliable access even at an industrial scale.&lt;/p&gt;
&lt;p&gt;PostgreSQL is selected as the first database offering in FlowFuse Tables because it is flexible, reliable, and open source. It serves as a solid foundation for FlowFuse Tables. Whether your data comes from IIoT sensors or other sources, PostgreSQL is well equipped to handle it.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we begin, please ensure you have the following set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A FlowFuse Enterprise account, as FlowFuse Tables is an exclusive Enterprise feature.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; package installed in your FlowFuse instance to create the user interface.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;node-red-contrib-moment&lt;/code&gt; node installed for handling date and time operations within your flows.&lt;/li&gt;
&lt;li&gt;FlowFuse Tables configured for your FlowFuse Team with a managed PostgreSQL database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are new to FlowFuse Tables, we highly recommend reading our &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/&quot;&gt;getting started guide&lt;/a&gt; to familiarize yourself with the basics.&lt;/p&gt;
&lt;h2 id=&quot;creating-an-optimized-database-schema&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#creating-an-optimized-database-schema&quot;&gt;Creating an Optimized Database Schema&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our first step is to design a database table structured for both high-speed writes and efficient queries.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-design-and-create-the-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#step-1%3A-design-and-create-the-table&quot;&gt;Step 1: Design and Create the Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We will create a single table to hold all our sensor data. The key is to use appropriate data types and indexes to ensure performance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In your FlowFuse Node-RED instance, drag a &lt;strong&gt;Query node&lt;/strong&gt; onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the node with the following SQL statement to create the table and its indexes:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-70&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-70&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_readings&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SERIAL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt; TIMESTAMPTZ &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;location&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DECIMAL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;idx_sensor_timestamp&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_readings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-70&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Schema Breakdown:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TIMESTAMPTZ&lt;/code&gt;: We use this data type to store timestamps with timezone information. This is critical for applications with sensors spread across different geographical locations, ensuring data is always consistent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Index&lt;/strong&gt;: The composite index on &lt;code&gt;sensor_id&lt;/code&gt; and &lt;code&gt;timestamp&lt;/code&gt; (in descending order) is vital for query speed. It allows PostgreSQL to quickly locate and return results for a specific sensor while already ordering them from newest to oldest. This avoids expensive sorting when fetching the most recent readings for a given sensor.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The &lt;code&gt;DESC&lt;/code&gt; in the composite index provides a significant performance boost for queries like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-90&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-90&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; sensor_readings&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; sensor_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;sensor_01&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-90&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you instead need results in chronological order, you could create an ascending index or let PostgreSQL reverse the order at query time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;To execute this one-time setup, connect an &lt;strong&gt;Inject node&lt;/strong&gt; to the input of the &lt;strong&gt;Query node&lt;/strong&gt; and a &lt;strong&gt;Debug node&lt;/strong&gt; to its output.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;, then click the button on the &lt;strong&gt;Inject node&lt;/strong&gt; to create your table.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-2%3A-storing-sensor-data-efficiently-with-batch-inserts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#step-2%3A-storing-sensor-data-efficiently-with-batch-inserts&quot;&gt;Step 2: Storing Sensor Data Efficiently with Batch Inserts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Writing every single sensor reading to the database individually can create significant overhead and slow down performance. A much more efficient method is to &amp;quot;batch&amp;quot; readings together and write them in a single transaction.&lt;/p&gt;
&lt;p&gt;Let&#39;s build a flow to simulate sensor data and batch-insert it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;Inject node&lt;/strong&gt; configured to repeat every &lt;strong&gt;1 second&lt;/strong&gt; to simulate a continuous stream of data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect it to a &lt;strong&gt;Change node&lt;/strong&gt; that generates a simulated sensor reading. Configure it to set &lt;code&gt;msg.payload&lt;/code&gt; using the following JSONata expression:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-128&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-128&quot; class=&quot;language-json&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Production Line A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt; + $random() * &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-128&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Add another &lt;strong&gt;Change node&lt;/strong&gt; to add a precise timestamp to each reading.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To the value type &lt;strong&gt;timestamp&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Function node&lt;/strong&gt; and name it &lt;strong&gt;&amp;quot;Batch Accumulator&amp;quot;&lt;/strong&gt;. Paste the following JavaScript code into the node — it already includes inline comments explaining each step. This function will accumulate incoming readings in batches until the specified batch size is reached, and then creates the SQL query to perform batch inserts into the database.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-153&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-153&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the number of records to collect before triggering a batch insert&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; batchSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Retrieve previously stored readings from context (or start with an empty array)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; readings &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;readings&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Add the new reading (from msg.payload) to the readings array&lt;/span&gt;&lt;br /&gt;readings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Check if we have enough readings to perform a batch insert&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;readings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; batchSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Generate parameter placeholders for each reading (4 fields per record)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Example: ($1, $2, $3, $4), ($5, $6, $7, $8), ...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; readings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;br /&gt;        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;($&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Build the SQL insert query with placeholders&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;        INSERT INTO sensor_readings&lt;br /&gt;        (timestamp, sensor_id, location, temperature)&lt;br /&gt;        VALUES &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;values&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;&lt;br /&gt;    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Flatten the readings into a single array of values matching the placeholders&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// For each reading, we pass: current timestamp, sensor_id, location, temperature&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; readings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;// Or use r.timestamp if actual reading time is available&lt;/span&gt;&lt;br /&gt;        r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sensor_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temperature&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Clear stored readings in context now that they are being inserted&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;readings&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Return the msg with the SQL query and parameters for execution&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// If not enough readings collected yet, store them back into context&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;readings&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; readings&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Do not send anything forward yet&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-153&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &amp;quot;Batch Accumulator&amp;quot; to a &lt;strong&gt;Query node&lt;/strong&gt;. This node will receive the fully formed &lt;code&gt;msg.query&lt;/code&gt; and execute the batch insert.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow. It will now collect 100 readings (over 100 seconds) and perform a single, highly efficient database write instead of 100 separate ones.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;building-the-interactive-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#building-the-interactive-dashboard&quot;&gt;Building the Interactive Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With data flowing into our database, let&#39;s create a user interface to query and visualize it.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-create-an-interactive-time-range-selector&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#step-3%3A-create-an-interactive-time-range-selector&quot;&gt;Step 3: Create an Interactive Time Range Selector&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ll start with a form that allows users to select a date, time, and duration to view.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui_form&lt;/strong&gt; node onto the canvas. Create a new dashboard group for it and add the following form elements:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Form widget configuration showing date, time, and window duration fields&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Time Range Selector form configuration in Node-RED Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the form to a &lt;strong&gt;Change&lt;/strong&gt; node to format the input. Add the following rules in the Change node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;msg.startDateTime&lt;/code&gt; to the JSONata expression:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-196&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-196&quot; class=&quot;language-json&quot;&gt;payload.start &amp;amp; &lt;span class=&quot;token string&quot;&gt;&quot;T&quot;&lt;/span&gt; &amp;amp; payload.time &amp;amp; &lt;span class=&quot;token string&quot;&gt;&quot;:00&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-196&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;msg.windowMinutes&lt;/code&gt; to the expression:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-202&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-202&quot; class=&quot;language-json&quot;&gt;payload.window&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-202&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Date/Time Formatter&lt;/strong&gt; node. This is crucial for handling timezones correctly. Configure it as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input property:&lt;/strong&gt; &lt;code&gt;msg.startDateTime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input timezone:&lt;/strong&gt; your local timezone, for example, &lt;code&gt;Asia/Kolkata&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output timezone:&lt;/strong&gt; &lt;code&gt;Etc/UTC&lt;/code&gt; (to match the database &lt;code&gt;TIMESTAMPTZ&lt;/code&gt; standard)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output property:&lt;/strong&gt; &lt;code&gt;msg.startDateTime&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Date/Time Formatter node configuration showing timezone conversion settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/moment.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the Date/Time Formatter node to convert from local timezone to UTC&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add another &lt;strong&gt;Change&lt;/strong&gt; node to set the query parameters for the SQL query. Set &lt;code&gt;msg.params&lt;/code&gt; to the following JSONata expression:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
    msg.startDateTime,
    msg.windowMinutes &amp;amp; &amp;quot; minutes&amp;quot;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect this to a &lt;strong&gt;Query&lt;/strong&gt; node with the following parameterized SQL, which fetches data for the selected time window:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-246&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-246&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_readings&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor_id&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;sensor_01&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; $&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;::timestamptz&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;::timestamptz &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; $&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;::&lt;span class=&quot;token keyword&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-246&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect a &lt;strong&gt;Debug&lt;/strong&gt; node after the Query node to test the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and add a condition to check whether &lt;code&gt;msg.payload&lt;/code&gt; is empty. Connect the output of the Query node to the Switch node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the output for the &amp;quot;empty&amp;quot; condition from the Switch node to a &lt;strong&gt;Change&lt;/strong&gt; node that sets &lt;code&gt;msg.payload&lt;/code&gt; to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;No data found for the selected time range.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui_notification&lt;/strong&gt; node, select the appropriate UI group, and connect it to the output of the Change node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow. On the dashboard, select a &lt;strong&gt;date&lt;/strong&gt;, &lt;strong&gt;time&lt;/strong&gt;, and &lt;strong&gt;window&lt;/strong&gt; using the form. Verify in the debug panel that the correct data is returned, or that a notification appears if no data is found.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Complete time range selector form&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-time-range-selector.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Complete time range selector form&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-display-the-data-in-a-chart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#step-4%3A-display-the-data-in-a-chart&quot;&gt;Step 4: Display the Data in a Chart&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The final step is to visualize the query result.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the final &lt;strong&gt;Query node&lt;/strong&gt; to a &lt;strong&gt;ui_chart&lt;/strong&gt; widget.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the chart node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Group: Create new group for chart.&lt;/li&gt;
&lt;li&gt;Type: Line&lt;/li&gt;
&lt;li&gt;X: Set to &lt;code&gt;timestamp&lt;/code&gt; as a key.&lt;/li&gt;
&lt;li&gt;Y: Set to &lt;code&gt;temperature&lt;/code&gt; as a key.&lt;/li&gt;
&lt;li&gt;Series: Set to &amp;quot;Temperature&amp;quot; as string.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow. Your complete historical data dashboard is now live — you can explore it and experiment with different time ranges to see the results.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;historical data dashboard retrieving historical data nd displying it&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/historical-data-dashboard.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Historical data dashboard retrieving and displaying historical data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is the complete flow we built in this tutorial.&lt;/p&gt;
&lt;div id=&quot;nr-flow-243&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow243 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Flow 1&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;48b1380ff7bfe716&#92;&quot;,&#92;&quot;44bb8750d961e415&#92;&quot;,&#92;&quot;4a3976e062b2ddd2&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:59,&#92;&quot;w&#92;&quot;:572,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulate Sensor and perform batch insert&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e465d4328d9d42d9&#92;&quot;,&#92;&quot;50fb850e3e3db58e&#92;&quot;,&#92;&quot;b21d6dabf731e866&#92;&quot;,&#92;&quot;f8269cf412b4200f&#92;&quot;,&#92;&quot;96fdd4673919b0d2&#92;&quot;,&#92;&quot;04340ad3b984a2df&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:159,&#92;&quot;w&#92;&quot;:1092,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Historical data dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;f493229b28ac8c11&#92;&quot;,&#92;&quot;b9017676553dc100&#92;&quot;,&#92;&quot;322dee35a2d77015&#92;&quot;,&#92;&quot;f3ca555ef811453c&#92;&quot;,&#92;&quot;0cb8d32327a10533&#92;&quot;,&#92;&quot;b5dc2ed0fac07f02&#92;&quot;,&#92;&quot;f3bfdee87aab61f8&#92;&quot;,&#92;&quot;9481202eb7a507b6&#92;&quot;,&#92;&quot;159bd298de4a95d0&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:259,&#92;&quot;w&#92;&quot;:1612,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;4f24ab5b5628a1ba&#92;&quot;,&#92;&quot;fbf36a7b3c59461d&#92;&quot;],&#92;&quot;x&#92;&quot;:634,&#92;&quot;y&#92;&quot;:59,&#92;&quot;w&#92;&quot;:392,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;48b1380ff7bfe716&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;44bb8750d961e415&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;44bb8750d961e415&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;   CREATE TABLE &#92;&#92;&#92;&quot;sensor_readings&#92;&#92;&#92;&quot; (&#92;&#92;n       &#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot; SERIAL PRIMARY KEY,&#92;&#92;n       &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot; TIMESTAMPTZ NOT NULL DEFAULT NOW(),&#92;&#92;n       &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot; VARCHAR(50) NOT NULL,&#92;&#92;n       &#92;&#92;&#92;&quot;location&#92;&#92;&#92;&quot; VARCHAR(100),&#92;&#92;n       &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot; DECIMAL(5,2)&#92;&#92;n   );&#92;&#92;n&#92;&#92;n   CREATE INDEX &#92;&#92;&#92;&quot;idx_sensor_timestamp&#92;&#92;&#92;&quot; ON &#92;&#92;&#92;&quot;sensor_readings&#92;&#92;&#92;&quot;(&#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot; DESC);&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4a3976e062b2ddd2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4a3976e062b2ddd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e9a3b71d40addd8b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e465d4328d9d42d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;96fdd4673919b0d2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;50fb850e3e3db58e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Query&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;const batchSize = 100;&#92;&#92;nconst readings = context.get(&#39;readings&#39;) || [];&#92;&#92;n&#92;&#92;nreadings.push(msg.payload);&#92;&#92;n&#92;&#92;nif (readings.length &amp;gt;= batchSize) {&#92;&#92;n    // Prepare batch insert&#92;&#92;n    const values = readings.map((_, i) =&amp;gt; &#92;&#92;n        `($${i*7+1}, $${i*7+2}, $${i*7+3}, $${i*7+4}, $${i*7+5}, $${i*7+6}, $${i*7+7})`&#92;&#92;n    ).join(&#39;,&#39;);&#92;&#92;n    &#92;&#92;n    msg.query = `&#92;&#92;n        INSERT INTO &#92;&#92;&#92;&quot;sensor_readings&#92;&#92;&#92;&quot;&#92;&#92;n        (&#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;location&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;)&#92;&#92;n        VALUES ${values}&#92;&#92;n    `;&#92;&#92;n    &#92;&#92;n    msg.params = readings.flatMap(r =&amp;gt; [&#92;&#92;n        new Date(),&#92;&#92;n        r.sensor_id,&#92;&#92;n        r.location,&#92;&#92;n        r.temperature,&#92;&#92;n    ]);&#92;&#92;n    &#92;&#92;n    context.set(&#39;readings&#39;, []);&#92;&#92;n    return msg;&#92;&#92;n}&#92;&#92;n&#92;&#92;ncontext.set(&#39;readings&#39;, readings);&#92;&#92;nreturn null;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:890,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f8269cf412b4200f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b21d6dabf731e866&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Batch Accumulator&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Set the number of records to collect before triggering a batch insert&#92;&#92;nconst batchSize = 100;&#92;&#92;n&#92;&#92;n// Retrieve previously stored readings from context (or start with an empty array)&#92;&#92;nconst readings = context.get(&#39;readings&#39;) || [];&#92;&#92;n&#92;&#92;n// Add the new reading (from msg.payload) to the readings array&#92;&#92;nreadings.push(msg.payload);&#92;&#92;n&#92;&#92;n// Check if we have enough readings to perform a batch insert&#92;&#92;nif (readings.length &amp;gt;= batchSize) {&#92;&#92;n&#92;&#92;n    // Generate parameter placeholders for each reading (4 fields per record)&#92;&#92;n    // Example: ($1, $2, $3, $4), ($5, $6, $7, $8), ...&#92;&#92;n    const values = readings.map((_, i) =&amp;gt; &#92;&#92;n        `($${i * 4 + 1}, $${i * 4 + 2}, $${i * 4 + 3}, $${i * 4 + 4})`&#92;&#92;n    ).join(&#39;,&#39;);&#92;&#92;n&#92;&#92;n    // Build the SQL insert query with placeholders&#92;&#92;n    msg.query = `&#92;&#92;n        INSERT INTO sensor_readings&#92;&#92;n        (timestamp, sensor_id, location, temperature)&#92;&#92;n        VALUES ${values};&#92;&#92;n    `;&#92;&#92;n&#92;&#92;n    // Flatten the readings into a single array of values matching the placeholders&#92;&#92;n    // For each reading, we pass: current timestamp, sensor_id, location, temperature&#92;&#92;n    msg.params = readings.flatMap(r =&amp;gt; [&#92;&#92;n        r.timestamp,&#92;&#92;n        r.sensor_id,&#92;&#92;n        r.location,&#92;&#92;n        r.temperature&#92;&#92;n    ]);&#92;&#92;n&#92;&#92;n    // Clear stored readings in context now that they are being inserted&#92;&#92;n    context.set(&#39;readings&#39;, []);&#92;&#92;n&#92;&#92;n    // Return the msg with the SQL query and parameters for execution&#92;&#92;n    return msg;&#92;&#92;n}&#92;&#92;n&#92;&#92;n// If not enough readings collected yet, store them back into context&#92;&#92;ncontext.set(&#39;readings&#39;, readings);&#92;&#92;n&#92;&#92;nreturn null;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;50fb850e3e3db58e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f8269cf412b4200f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1040,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96fdd4673919b0d2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulate Sensor&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{&#92;&#92;t   &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;sensor_01&#92;&#92;&#92;&quot;,&#92;&#92;t   &#92;&#92;&#92;&quot;location&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Production Line A&#92;&#92;&#92;&quot;,&#92;&#92;t   &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;: 20 + $random() * 5&#92;&#92;t}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;04340ad3b984a2df&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;04340ad3b984a2df&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;01137d02c4832962&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add timestamp&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.timestamp&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;iso&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;date&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:540,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b21d6dabf731e866&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f493229b28ac8c11&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;92613690554d5bb9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Historical Data Chart&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;timestamp&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;ccc HH:mm&#92;&quot;,&#92;&quot;xmin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xmax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;temperature&#92;&quot;,&#92;&quot;yAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bins&#92;&quot;:10,&#92;&quot;action&#92;&quot;:&#92;&quot;replace&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#a347e1&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:8,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;interpolation&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;x&#92;&quot;:1540,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9017676553dc100&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-form&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;b9e9762c81b55a05&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Start&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;start&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Time&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Window (minutes)&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;window&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;number&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null}],&#92;&quot;formValue&#92;&quot;:{&#92;&quot;start&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;time&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;window&#92;&quot;:&#92;&quot;&#92;&quot;},&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;submit&#92;&quot;:&#92;&quot;submit&#92;&quot;,&#92;&quot;cancel&#92;&quot;:&#92;&quot;clear&#92;&quot;,&#92;&quot;resetOnSubmit&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;splitLayout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;dropdownOptions&#92;&quot;:[],&#92;&quot;x&#92;&quot;:130,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;322dee35a2d77015&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;322dee35a2d77015&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;startDateTime&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.start &amp;amp; &#92;&#92;&#92;&quot;T&#92;&#92;&#92;&quot; &amp;amp; payload.time &amp;amp; &#92;&#92;&#92;&quot;:00&#92;&#92;&#92;&quot;&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;windowMinutes&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.window&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0cb8d32327a10533&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f3ca555ef811453c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;   SELECT &#92;&#92;n       &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot;,&#92;&#92;n       &#92;&#92;&#92;&quot;temperature&#92;&#92;&#92;&quot;&#92;&#92;n   FROM &#92;&#92;&#92;&quot;sensor_readings&#92;&#92;&#92;&quot;&#92;&#92;n   WHERE &#92;&#92;&#92;&quot;sensor_id&#92;&#92;&#92;&quot; = &#39;sensor_01&#39;&#92;&#92;n     AND &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot; &amp;gt;= $1::timestamptz&#92;&#92;n     AND &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot; &amp;lt; ($1::timestamptz + $2::interval) ORDER BY &#92;&#92;&#92;&quot;timestamp&#92;&#92;&#92;&quot; DESC;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:930,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f493229b28ac8c11&#92;&quot;,&#92;&quot;f3bfdee87aab61f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0cb8d32327a10533&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;moment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;input&#92;&quot;:&#92;&quot;startDateTime&#92;&quot;,&#92;&quot;inputType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;inTz&#92;&quot;:&#92;&quot;Asia/Kolkata&#92;&quot;,&#92;&quot;adjAmount&#92;&quot;:0,&#92;&quot;adjType&#92;&quot;:&#92;&quot;days&#92;&quot;,&#92;&quot;adjDir&#92;&quot;:&#92;&quot;add&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;locale&#92;&quot;:&#92;&quot;en-US&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;startDateTime&#92;&quot;,&#92;&quot;outputType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;outTz&#92;&quot;:&#92;&quot;ETC/UTC&#92;&quot;,&#92;&quot;x&#92;&quot;:540,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5dc2ed0fac07f02&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5dc2ed0fac07f02&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set Params&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[     msg.startDateTime,     msg.windowMinutes &amp;amp; &#92;&#92;&#92;&quot; minutes&#92;&#92;&#92;&quot;   ]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f3ca555ef811453c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f3bfdee87aab61f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Is payload empty?&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;empty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9481202eb7a507b6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9481202eb7a507b6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Notification Message&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;No data found for the selected time range.&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;159bd298de4a95d0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;159bd298de4a95d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;89c860a27ff3db10&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;allowConfirm&#92;&quot;:false,&#92;&quot;confirmText&#92;&quot;:&#92;&quot;Confirm&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1530,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4f24ab5b5628a1ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scope&#92;&quot;:null,&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fbf36a7b3c59461d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fbf36a7b3c59461d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;901337216b60b25a&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;68fbcdb03e3a5346&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 6&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:920,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;92613690554d5bb9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Historical Chart&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d03a38650bf3082f&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9e9762c81b55a05&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Form&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d03a38650bf3082f&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;UI Name&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-notification&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;icon&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:5,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;d03a38650bf3082f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Historical Data Dashboard&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;afea04ce8735c0a6&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/historical-data&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;6d8bff5f3fded5c2&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:3,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;6d8bff5f3fded5c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;FF Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#5046e5&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#5046e5&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#d4d1ff&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;15px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;15px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;a0dab2a5f9f4e3d2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/nr-tables-nodes&#92;&quot;:&#92;&quot;0.1.0&#92;&quot;,&#92;&quot;@flowfuse/node-red-dashboard&#92;&quot;:&#92;&quot;1.26.0&#92;&quot;,&#92;&quot;node-red-contrib-moment&#92;&quot;:&#92;&quot;5.0.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow243.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-243&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/time-series-dashboard-flowfuse-postgresql/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You have successfully built a historical data dashboard using FlowFuse Tables and Node-RED. By implementing efficient batch inserts and optimized query patterns, you have created a solution that is both powerful and scalable for demanding Industrial IoT environments.&lt;/p&gt;
&lt;p&gt;With FlowFuse Tables now part of the platform, you can build complete industrial applications without juggling external databases or leaving the FlowFuse environment. FlowFuse is now a comprehensive data platform with the ability to collect, connect, transform, store, and visualize data. Combined with FlowFuse&#39;s enterprise features—team collaboration, version control, device management, and secure deployments—you have everything needed to take your IIoT projects from prototype to production within one integrated platform.&lt;/p&gt;
&lt;p&gt;This means less complexity and faster time to value for your industrial data initiatives. Your historical dashboards, real-time monitoring, and OEE dashboards can all live in the same ecosystem, managed by the same team, with consistent security and governance controls.&lt;/p&gt;
&lt;p&gt;Ready to build your own time-series dashboard? &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started with FlowFuse Tables&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/blueprints/&quot;&gt;explore our industrial blueprints&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/</id>
        <title>Winning Through Open-Source Software in Manufacturing Digitalization</title>
        <summary>Manufacturing organizations used to be leading in software but has lost the lead. Open Source Software is the way to now catch up</summary>
        <updated>2025-08-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;The manufacturing sector is in an interesting situation. It&#39;s caught between a
future with immense promise and a present with high complexity. The promised ROI
of digital transformation (DX) is into the
&lt;a href=&quot;https://www.marketresearchfuture.com/reports/digital-transformation-in-manufacturing-market-32040&quot;&gt;trillions of dollars&lt;/a&gt;
globally over the next decade. For manufacturers, this is more than just an
opportunity for incremental improvement; it is a fundamental shift to
competitiveness.&lt;/p&gt;
&lt;p&gt;Yet, on the other hand, a starkly different narrative is heard from the factory
floor. Despite the commitment of many IT and OT teams, paired with colossal
investment, the path to digitalization is proving to be unexpectedly slow. About
70% of digital transformation projects are (self-reported!)
&lt;a href=&quot;https://www.myhubintranet.com/digital-transformation-statistics/&quot;&gt;considered failures&lt;/a&gt;.
Falling short of their objectives and failing to deliver the promised return on
investment (ROI).&lt;/p&gt;
&lt;p&gt;To break this impasse a strategic shift and pivot will be needed, industrial IT
and OT need a decisive pivot to open-source software (OSS). With its core
principles of collaboration, transparency, and interoperability—manufacturers
can systematically remove barriers that have slowed their DX. Open source
provides the tools and the philosophy necessary to acquire and transport data
more effectively, build powerful analytics and interaction applications that
deliver real ROI, and, most of all, escape vendor lock-in.&lt;/p&gt;
&lt;h2 id=&quot;the-digitalization-paradox-in-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/#the-digitalization-paradox-in-manufacturing&quot;&gt;The Digitalization Paradox in Manufacturing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The economic case for digital transformation in manufacturing is unequivocal and
immense. The global digital transformation market, valued at nearly $1 trillion
in 2020, is forecasted to be
&lt;a href=&quot;https://www.themanufacturer.com/articles/digital-transformation-in-manufacturing-the-challenges/&quot;&gt;over $2.7 trillion by 2026&lt;/a&gt;.
This growth is driven by the operational benefits; the primary motivators for
these investments are to achieve greater operational efficiency (cited by 40% of
executives), a faster time-to-market for new products (36%), and an improved
customer experience (35%).&lt;/p&gt;
&lt;p&gt;To understand the paradox, one must dissect why manufacturing initiatives fail.
These challenges are connected with one-another, and are symptom from more
systemic issues. Financial constraints and ROI, particularly high initial costs
for hardware, software, and integration, coupled with pressure for rapid ROI,
create a catch-22. DX is now viewed as a cost center rather than a source of
operational improvement and thus ROI. A lack of qualified workers and in-house
skills, especially in IT, is another roadblock. With manufacturing competing for
talent with tech and finance. Then there’s legacy systems, where factory floors
have old, incompatible machinery and systems, making upgrading or retrofitting
this &amp;quot;rigid infrastructure&amp;quot; costly and complex, often stalling or killing
projects. Finally, cybersecurity fears arise from increased connectivity in
factories, expanding the attack surface and making the implementation of robust
and costly cybersecurity solutions complex, especially for SMEs.&lt;/p&gt;
&lt;h2 id=&quot;the-iron-grip-of-proprietary-systems-and-vendor-lock-in&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/#the-iron-grip-of-proprietary-systems-and-vendor-lock-in&quot;&gt;The Iron Grip of Proprietary Systems and Vendor Lock-In&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The challenges detailed in the earlier, stem from the same key issue – the
manufacturing industry&#39;s historical and continued reliance on a technological
paradigm built around closed, proprietary systems. This licensing model, which
was key in enabling the first wave of digital automation, has now become a
barrier. Its defining characteristic is vendor lock-in, a condition that
systematically stifles innovation, inflates licensing costs, and holds the
industrial sector as a whole back from progress.&lt;/p&gt;
&lt;p&gt;Innovation has always driven industrial automation forward. The transition from
mechanical systems to electrical relay logic in the early 20th century, and then
to the maturing of Programmable Logic Controller (PLC) in the 1960s, transformed
the factory floor. PLCs, followed by Supervisory Control and Data Acquisition
(SCADA) and Distributed Control Systems (DCS), brought control, reliability, and
programmability to industrial processes. These technologies were the engines of
the Third Industrial Revolution. Industrial automation was leading the way in
what was possible with digital systems, and combining these systems with one
another in new ways. The manufacturers were driving innovation in the software
industry and gaining real momentous ROI.&lt;/p&gt;
&lt;p&gt;Since the late seventies, software became a copywrightable good, and with a shift
happened mostly in traditional applications of the software – Vendor Lock-In.&lt;/p&gt;
&lt;p&gt;Vendor lock-in is an economic and technical condition where a customer becomes
so dependent on a specific vendor&#39;s products and services that switching to an
alternative provider becomes prohibitively difficult or costly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With that, manufacturers used to lead the way three quarters into the 20th
century, now are stuck with their 21st-century digital ambitions.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The traditional, vertically integrated model of industrial digitalization,
‘featuring’ vendor lock-in, is a critical hindrance currently. This paradigm now
showcases inflated costs, lack of innovation, interoperability issues, and a
skills gap. These issues have effectively made manufacturers followers rather
than leaders in the realm of software-aided business. To regain an edge a
fundamental shift is a requirement. This shift requires abandoning vertical
point-solutions and instead embracing a new technological foundation that is
inherently open, fostering interoperability, and freeing manufacturers from the
constraints of single-vendor control.&lt;/p&gt;
&lt;h2 id=&quot;dx-with-open-source-software&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/#dx-with-open-source-software&quot;&gt;DX with Open-Source Software&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In contrast to the closed, proprietary software, the open-source variant offers
a fresh approach to creating and distributing software. Born from the need of
collaboration and transparency, open-source software (OSS) provides fundamentals
to break vendor lock-in once and for all.&lt;/p&gt;
&lt;p&gt;In 1983, MIT programmer Richard Stallman, annoyed by the practice of withholding
source code, founded the Free Software Foundation. His goal was to create a
completely free (“Free” as in speech, and also “Free” as in beer) operating
system, establishing a philosophy built on the user&#39;s right to run, study,
modify, and redistribute software. In the late 1990s, this movement gained a
more pragmatic and business-friendly identity with the coining of the term &amp;quot;open
source&amp;quot;.&lt;/p&gt;
&lt;p&gt;The value proposition of OSS is great and shows up in four key points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cost-Effectiveness&lt;/li&gt;
&lt;li&gt;High flexibility and extensibility&lt;/li&gt;
&lt;li&gt;Cross-Industry collaboration&lt;/li&gt;
&lt;li&gt;Stability and Strategic Control&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To go over each, one by one.&lt;/p&gt;
&lt;p&gt;The most immediate appeal of OSS is the absence of high upfront licensing fees.
OSS is not &amp;quot;free&amp;quot; when considering the total cost of ownership (TCO), which
includes implementation, integration, training, and support. The crucial
difference lies in where the money goes. With proprietary software, a large
portion of the budget is spent on license and maintenance fees that primarily
benefit the vendor. With OSS, that same capital can be reinvested into
activities that build direct value for the manufacturer.&lt;/p&gt;
&lt;p&gt;Secondly, flexibility of software and freedom to extend it – the single most
powerful advantage of OSS. Because the source code is accessible, manufacturers
are no longer constrained by a vendor&#39;s limited feature set or development
roadmap. Anyone can propose changes that modify, adapt, and extend the software
to meet their operational needs. If a particular open-source tool doesn&#39;t
support a niche industrial protocol, the company has the option to build that
integration itself or hire a third party to do so. As these investments do not
provide an edge over competition, it’s almost always shared within the OSS
community – building libraries of open toolchains.&lt;/p&gt;
&lt;p&gt;Extending on that; Cross-industry collaboration enables wildly different
use-cases with the same fundamental problems to resolve to apply their knowledge
and craft serving all other businesses. For example, database technology has
been perfected for decades by banking and trading companies to allow for atomic
transactions and durability of data of those transactions. These scalability
improvements have profound impact for manufacturing use-cases around the world,
helping out with compliance, track-and-trace, and more.&lt;/p&gt;
&lt;p&gt;Finally, Long-Term Stability and Strategic Control is implicitly featured with
OSS. With proprietary software, a manufacturer is exposed to the business risks
of the vendor. If the vendor is acquired, goes out of business, or simply
decides to discontinue a product line, the manufacturer can be left with an
unsupported and obsolete system. With OSS, the code is publicly distributed and
cannot be withdrawn. Even if the original maintainers abandon a project, the
community—or the company itself—can &amp;quot;fork&amp;quot; the code and continue its
development. This provides a level of long-term stability and strategic control
over critical technology assets that is impossible to achieve in a
vendor-dependent relationship.&lt;/p&gt;
&lt;h2 id=&quot;finale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/open-source-software-and-manufacturing/#finale&quot;&gt;Finale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The manufacturing industry faces a challenge with its digital transformation
efforts. A reliance on proprietary systems has contributed to an impasse where
investment does not always produce the expected results. This model,
characterized by vendor lock-in, can lead to higher costs and constraints on
innovation, causing manufacturers to lag in technology adoption.&lt;/p&gt;
&lt;p&gt;To move forward, a different approach can be considered. Open-source software
(OSS) offers a model that addresses many of the barriers causing digital
transformation projects to fail. With OSS, companies can gain more strategic
control over their technology, redirect funds from licensing fees toward
in-house capabilities, and connect previously isolated systems. This allows a
manufacturer to shift from being a consumer of a vendor&#39;s technology to a
director of its own.&lt;/p&gt;
&lt;p&gt;The conversation is therefore shifting from if manufacturing should adopt open
source, to how it can be implemented to improve operations and deliver a return
on investment. This transition presents new questions, but it is one that
companies do not have to approach on their own. At FlowFuse, we work with
manufacturers to navigate this change, and we would love to explain how an
open-source strategy can transform your factory of the future. Download our comprehensive whitepaper &amp;quot;&lt;a href=&quot;https://flowfuse.com/whitepaper/open-source-software-for-manufacturing/&quot;&gt;Open Source Software for Manufacturing&lt;/a&gt;,&amp;quot; to learn how to transform your factory operations and secure a competitive edge.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/</id>
        <title>OPC UA Tutorial: Advanced Monitoring with Subscriptions, Alarms, and Historical Data</title>
        <summary>Master advanced OPC UA features in Node-RED for production-ready industrial automation</summary>
        <updated>2025-08-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In our &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;previous tutorial&lt;/a&gt;, we covered OPC UA basics—connecting to servers, reading tags, and writing values. Now it&#39;s time for the features that make OPC UA truly powerful in production.&lt;/p&gt;
&lt;p&gt;Polling for data every few seconds works fine for demos, but real systems need better. They need instant updates when values change. They need alarms that fire immediately when something goes wrong. They need access to historical data for troubleshooting. And they need to trigger complex operations without juggling dozens of write commands.&lt;/p&gt;
&lt;p&gt;This guide shows you how to build all of that using advanced OPC UA features in FlowFuse Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;what-you&#39;ll-learn&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#what-you&#39;ll-learn&quot;&gt;What You&#39;ll Learn&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide covers four powerful OPC UA features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Subscriptions&lt;/strong&gt;: Get real-time updates without constant polling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Events &amp;amp; Alarms&lt;/strong&gt;: Capture and handle equipment alerts as they happen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Historical Data&lt;/strong&gt;: Query past values for trending and analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Method Calls&lt;/strong&gt;: Execute functions directly on your equipment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To follow this guide, you&#39;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FlowFuse running instance with the &lt;code&gt;node-red-contrib-opcua&lt;/code&gt; nodes installed&lt;/li&gt;
&lt;li&gt;A working OPC UA server connection&lt;/li&gt;
&lt;li&gt;The basics from our &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;previous tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Managing and scaling Node-RED instances is easy with FlowFuse, offering DevOps pipelines, audit logs, snapshots, high availability, and much more. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start your free trial today!&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before proceeding, check which features your OPC UA server supports—most handle subscriptions and events, but historical data and methods vary by vendor.&lt;/p&gt;
&lt;p&gt;Let&#39;s get started.&lt;/p&gt;
&lt;h2 id=&quot;real-time-monitoring-with-subscriptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#real-time-monitoring-with-subscriptions&quot;&gt;Real-Time Monitoring with Subscriptions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA subscriptions monitor values on the server side and notify you only when they change. This is fundamentally different from polling, where you repeatedly ask for values whether they&#39;ve changed or not.&lt;/p&gt;
&lt;p&gt;Consider a pressure sensor that spikes from 5 to 20 bar and back to 5 bar in one second. With 2-second polling, you miss this critical event entirely. With subscriptions, the server captures it and notifies you immediately.&lt;/p&gt;
&lt;p&gt;The efficiency gains are significant too. Monitoring 100 tags with polling means 100 requests every 2 seconds, consuming bandwidth even when nothing changes. Subscriptions send updates only when values actually change, reducing network traffic and server load.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-subscriptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#setting-up-subscriptions&quot;&gt;Setting Up Subscriptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To create your first subscription:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto your canvas. This will trigger the subscription to start.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: This article uses Inject nodes for manual triggering to illustrate key concepts. In production, it is advisable to create interactive dashboards with FlowFuse Dashboard to enable effective monitoring and control. For more information on designing operator interfaces, please refer to &lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Item node. Double-click it and enter the NodeId of the tag you want to monitor, like &lt;code&gt;ns=2;i=2007&lt;/code&gt;. Select the correct data type for your tag.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Place an OpcUa-Client node on the canvas. Open its Configuration, select your OPC UA server endpoint configuration, and change the Action dropdown to &amp;quot;SUBSCRIBE&amp;quot;. Set the interval to how often you want updates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject output to the OpcUa-Item input. Connect the OpcUa-Item output to the OpcUa-Client input. Add a Debug node and connect the OpcUa-Client output to the Debug input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy your flow and click the Inject button.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-233&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow233 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c62e8dab346d62bb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7008401a.b94db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cce9159a656858b9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cce9159a656858b9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7008401a.b94db&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=3;i=1003&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Int32&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;042a5d016ce879c6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c1d56834b8d3373&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7008401a.b94db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1130,&#92;&quot;y&#92;&quot;:720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bccca1356626f117&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7008401a.b94db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1130,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;042a5d016ce879c6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7008401a.b94db&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;subscribe&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1c1d56834b8d3373&#92;&quot;],[&#92;&quot;bccca1356626f117&#92;&quot;],[]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow233.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-233&#39;) })&lt;/script&gt;
&lt;p&gt;When clicked, the OpcUa-Item node sends the tag to the OpcUa-Client and creates the subscription. The node’s status will update to “subscribed” once the subscription is active. When values change, they appear in the debug panel. If no value changes occur within the interval time, the status will show “keep alive” to confirm that the connection is still active.&lt;/p&gt;
&lt;h3 id=&quot;subscribing-to-multiple-tags&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#subscribing-to-multiple-tags&quot;&gt;Subscribing to Multiple Tags&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To monitor multiple tags, simply create multiple OpcUa-Item nodes and connect them all to the OpcUa-Client node. Each item node should have its own NodeId configured. When you trigger the flow, all tags start updating simultaneously.&lt;/p&gt;
&lt;p&gt;For many tags, you can also use a Function node to subscribe to multiple tags at once. Connect the Function node directly to the OpcUa-Client node (no OpcUa-Item node needed). Use the &amp;quot;multiple&amp;quot; topic with the following code:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-136&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-136&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;multiple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nodeId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=3;i=1007&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nodeId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=3;i=1002&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nodeId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=3;i=1001&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-136&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Below is the complete flow monitoring multiple tags:&lt;/p&gt;
&lt;div id=&quot;nr-flow-234&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow234 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;93d8a766.c57aa8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;NodeId Array&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.payload = [];&#92;&#92;nmsg.payload.push({ nodeId: &#92;&#92;&#92;&quot;ns=3;i=1001&#92;&#92;&#92;&quot;});&#92;&#92;nmsg.payload.push({ nodeId: &#92;&#92;&#92;&quot;ns=3;i=1002&#92;&#92;&#92;&quot;});&#92;&#92;nmsg.payload.push({ nodeId: &#92;&#92;&#92;&quot;ns=3;i=1003&#92;&#92;&#92;&quot;});&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ba45b808.7ff578&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d805dd3.473632&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Subscribe multiple&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;multiple&#92;&quot;,&#92;&quot;x&#92;&quot;:230,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;93d8a766.c57aa8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba45b808.7ff578&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;subscribe&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8d7ef05fbd80d2f9&#92;&quot;],[&#92;&quot;591cb7f46dd507af&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8d7ef05fbd80d2f9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;591cb7f46dd507af&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow234.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-234&#39;) })&lt;/script&gt;
&lt;p&gt;This subscribes to all tags in the array with a single request.&lt;/p&gt;
&lt;p&gt;When using the &amp;quot;multiple&amp;quot; topic, each value update arrives in OPC UA&#39;s DataValue format. Here&#39;s what you&#39;ll see in the debug panel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    value: {
        dataType: &amp;quot;Double&amp;quot;,
        value: 23.5
    },
    statusCode: {
        value: 0,  // 0 = Good
        description: &amp;quot;Good&amp;quot;
    },
    serverTimestamp: &amp;quot;2025-07-24T11:12:45.640Z&amp;quot;,
    sourceTimestamp: &amp;quot;2025-07-24T10:33:17.697Z&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Subscribing to multiple tags with OpcUa-Item nodes returns just the value.&lt;/p&gt;
&lt;h3 id=&quot;stopping-subscriptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#stopping-subscriptions&quot;&gt;Stopping Subscriptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To stop receiving updates and free up server resources, you have two options:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UNSUBSCRIBE&lt;/strong&gt;: Removes specific monitored items from the subscription but keeps the subscription alive. Use this when you want to stop monitoring certain tags while keeping others active.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DELETESUBSCRIPTION&lt;/strong&gt;: Completely removes the subscription and all its monitored items. Use this when you&#39;re done monitoring and want to clean up all resources.&lt;/p&gt;
&lt;p&gt;To use either action, change the OpcUa-Client node&#39;s Action dropdown to &amp;quot;unsubscribe&amp;quot; or &amp;quot;deletesubscription&amp;quot;.&lt;/p&gt;
&lt;h2 id=&quot;events-and-alarms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#events-and-alarms&quot;&gt;Events and Alarms&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA events and alarms go beyond simple value monitoring. While subscriptions tell you &amp;quot;the temperature is 95°C&amp;quot;, events tell you &amp;quot;high temperature alarm triggered at 14:32:15 on Tank 3&amp;quot;.&lt;/p&gt;
&lt;p&gt;Events capture the full context of what happened, when it happened, and what needs attention. Alarms are a special type of event that requires acknowledgment - perfect for critical situations that need human intervention.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-event-monitoring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#setting-up-event-monitoring&quot;&gt;Setting Up Event Monitoring&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an Inject node to trigger the event subscription.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Event node and configure the Source node to the event source. For server-wide events, use &lt;code&gt;ns=0;i=2253&lt;/code&gt; (the Server object).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Client node with Action set to &amp;quot;EVENTS&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject output to the OpcUa-Item node input. Connect the OpcUa-Item output to the OpcUa-Client input. Add a Debug node and connect the OpcUa-Client output to the Debug input.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Deploy and trigger the flow. The debug panel will show events as they occur on your server.&lt;/p&gt;
&lt;div id=&quot;nr-flow-235&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow235 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d72f52a6.35fa3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5d665294.f65f14&#92;&quot;,&#92;&quot;root&#92;&quot;:&#92;&quot;ns=0;i=2253&#92;&quot;,&#92;&quot;activatecustomevent&#92;&quot;:false,&#92;&quot;eventtype&#92;&quot;:&#92;&quot;i=2041&#92;&quot;,&#92;&quot;customeventtype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;All events&#92;&quot;,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ae628046.ca67c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96c3ea4c.7897e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5d665294.f65f14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Subscribe events&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d72f52a6.35fa3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ae628046.ca67c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5d665294.f65f14&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;events&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;time&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;Prosys events&#92;&quot;,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;67203130.a7a05&#92;&quot;],[&#92;&quot;1a7bf6600cc8bec0&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;67203130.a7a05&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5d665294.f65f14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a7bf6600cc8bec0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5d665294.f65f14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errrors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow235.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-235&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;acknowledging-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#acknowledging-events&quot;&gt;Acknowledging Events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When alarms trigger, operators often need to acknowledge them to indicate they&#39;ve seen the issue. Here&#39;s how to send acknowledgments back to the OPC UA server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an Inject node to manually trigger the acknowledgment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a Function node to prepare the acknowledgment message.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Function node, add the following code. Comments within the code explain what needs to be replaced.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-227&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-227&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=6;s=MyLevel.Alarm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// The alarm&#39;s NodeId&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;conditionId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=6;s=MyLevel.Alarm/0:EventId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// NodeId + &quot;/0:EventId&quot;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;comment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Acknowledged via Node-RED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Your acknowledgment message&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-227&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Client node and configure it with your OPC UA server endpoint. Open the node’s configuration and set the Action dropdown to &amp;quot;ACKNOWLEDGE&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject output to the Function input. Connect the Function output to the OpcUa-Client input.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-236&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow236 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;99a5c133.d9bdb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Acknowledge event&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cf182b3.04017d8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cf182b3.04017d8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AlarmID and EventID&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.topic = &#92;&#92;&#92;&quot;ns=6;s=MyLevel.Alarm&#92;&#92;&#92;&quot;;&#92;&#92;nmsg.conditionId = &#92;&#92;&#92;&quot;ns=6;s=MyLevel.Alarm/0:EventId&#92;&#92;&#92;&quot;;&#92;&#92;nmsg.comment = &#92;&#92;&#92;&quot;Node-RED OPCUA Ack&#92;&#92;&#92;&quot;;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;af39662a.1fd078&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;39a1c77b1fb33695&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e50779c74918b1b9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errrors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af39662a.1fd078&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;acknowledge&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;time&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA Client&#92;&quot;,&#92;&quot;x&#92;&quot;:640,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;39a1c77b1fb33695&#92;&quot;],[&#92;&quot;e50779c74918b1b9&#92;&quot;],[]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow236.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-236&#39;) })&lt;/script&gt;
&lt;p&gt;Deploy the flow. When you click the Inject button, it sends the acknowledgment to the server. The alarm state changes to &amp;quot;Event: &amp;lt;alarm&#39;s NodeId&amp;gt; Acknowledged&amp;quot; and operators know someone has seen the issue.&lt;/p&gt;
&lt;h2 id=&quot;method-calls&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#method-calls&quot;&gt;Method Calls&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA methods let you execute functions directly on your equipment. Instead of writing multiple values to trigger an action, you call a method with parameters—like calling a function in code.&lt;/p&gt;
&lt;p&gt;Methods are ideal for complex operations like starting batch processes, resetting counters, or triggering calibration routines. They encapsulate the logic on the server side, making your Node-RED flows simpler and more reliable.&lt;/p&gt;
&lt;h3 id=&quot;calling-methods&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#calling-methods&quot;&gt;Calling Methods&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To call a method on your OPC UA server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an Inject node to trigger the method call.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Method node and double-click it. Select your OPC UA endpoint, then enter the Object ID (like &lt;code&gt;ns=6;s=MyDevice&lt;/code&gt;) and Method ID (like &lt;code&gt;ns=6;s=MyMethod&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Arguments section, enter each argument&#39;s name, type, and value. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;Operator&lt;/code&gt;, Type: &lt;code&gt;String&lt;/code&gt;, Value: &amp;quot;sin&amp;quot;&lt;/li&gt;
&lt;li&gt;Name: &lt;code&gt;Value&lt;/code&gt;, Type: &lt;code&gt;Double&lt;/code&gt;, Value: &lt;code&gt;3.3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject output to the OpcUa-Method input. Add a Debug node to see the result.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-237&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow237 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;9b199c7f.82f47&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Method&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4d24eae5.3b9b24&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;objectId&#92;&quot;:&#92;&quot;ns=6;s=MyDevice&#92;&quot;,&#92;&quot;methodId&#92;&quot;:&#92;&quot;ns=6;s=MyMethod&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Prosys MyMethod(sin, 3.3)&#92;&quot;,&#92;&quot;inputArguments&#92;&quot;:[],&#92;&quot;arg0name&#92;&quot;:&#92;&quot;Operator&#92;&quot;,&#92;&quot;arg0type&#92;&quot;:&#92;&quot;String&#92;&quot;,&#92;&quot;arg0typeid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;arg0value&#92;&quot;:&#92;&quot;sin&#92;&quot;,&#92;&quot;arg1name&#92;&quot;:&#92;&quot;Value&#92;&quot;,&#92;&quot;arg1type&#92;&quot;:&#92;&quot;Double&#92;&quot;,&#92;&quot;arg1typeid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;arg1value&#92;&quot;:&#92;&quot;3.3&#92;&quot;,&#92;&quot;arg2name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;arg2type&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;arg2typeid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;arg2value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;out0name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;out0type&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;out0typeid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;out0value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aad9fc2a.a94b4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aad9fc2a.a94b4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4d24eae5.3b9b24&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;x&#92;&quot;:970,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6188d1de770fbb95&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4d24eae5.3b9b24&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Call Method&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9b199c7f.82f47&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow237.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-237&#39;) })&lt;/script&gt;
&lt;p&gt;Deploy and click the Inject button. The method executes on the server and the node status changes to &amp;quot;Method Executed&amp;quot;. The result appears in the debug panel.&lt;/p&gt;
&lt;h2 id=&quot;historical-data-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#historical-data-access&quot;&gt;Historical Data Access&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OPC UA Historical Access lets you query past values from your equipment. Instead of just seeing current temperature, you can ask &amp;quot;what was the temperature yesterday at 3 PM?&amp;quot; or &amp;quot;show me all pressure values from the last shift.&amp;quot;&lt;/p&gt;
&lt;p&gt;This is essential for troubleshooting, compliance reporting, and trend analysis. However, not all OPC UA servers support historical data—check your server documentation first. Also, not all tags are configured for history—verify that the &amp;quot;Historizing&amp;quot; attribute is set to true for your tag.&lt;/p&gt;
&lt;h3 id=&quot;reading-historical-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#reading-historical-values&quot;&gt;Reading Historical Values&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To query historical data from your server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an Inject node to trigger the historical read.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a Function node to prepare the query parameters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Function node, add this code:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-329&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-329&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NodeId ns=6;s=MyLevel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Replace with your NodeId&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aggregate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;raw&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Or use: &quot;min&quot;, &quot;max&quot;, &quot;ave&quot;, &quot;interpolative&quot;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1 hour ago&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Now&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-329&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Add an OpcUa-Client node. Open its configuration and set the Action dropdown to &amp;quot;HISTORY&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject output to the Function input. Connect the Function output to the OpcUa-Client input. Add a Debug node to see the historical values.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-238&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow238 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;0c43bd35230132af&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;history&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;532ae640b386e34e&#92;&quot;],[&#92;&quot;24678e079b08c81d&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5d8f9b5854a12919&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Historical Data&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9c071e5a8e543eba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9c071e5a8e543eba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.topic = &#92;&#92;&#92;&quot;ns=3;i=1001&#92;&#92;&#92;&quot;;&#92;&#92;nmsg.aggregate = &#92;&#92;&#92;&quot;ave&#92;&#92;&#92;&quot;;  // Try: &#92;&#92;&#92;&quot;min&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;max&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;ave&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;interpolative&#92;&#92;&#92;&quot;&#92;&#92;nmsg.start = new Date(Date.now() - 60 * 60 * 1000); // 1 hour ago&#92;&#92;nmsg.end = new Date(); // Now&#92;&#92;nmsg.interval = 300000;  // Required for aggregates: 5-minute intervals&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0c43bd35230132af&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;532ae640b386e34e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;24678e079b08c81d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58b3ba58c45b22dd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errrors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow238.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-238&#39;) })&lt;/script&gt;
&lt;p&gt;Deploy and click the Inject button. The debug panel shows all stored values for that tag within your time range.&lt;/p&gt;
&lt;h3 id=&quot;advanced-historical-queries&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#advanced-historical-queries&quot;&gt;Advanced Historical Queries&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While all historized tags support raw data, aggregate support varies by tag type. Analog values typically support aggregates like min, max, and ave, while discrete tags may only support raw.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Working with Aggregates:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-355&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-355&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=6;s=MyLevel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aggregate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ave&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Options: &quot;min&quot;, &quot;max&quot;, &quot;ave&quot;, &quot;interpolative&quot;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1 hour ago&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Now&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Required for aggregates: 5-minute intervals&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-355&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Hourly Averages for the Last Day:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-359&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-359&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=3;s=Temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aggregate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ave&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 24 hours ago&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 1-hour intervals&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-359&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Peak Detection:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-363&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-363&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Find maximum values in 15-minute windows&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=3;s=Pressure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aggregate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setHours&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Midnight today&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;900000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 15-minute intervals&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-363&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The historical data returns with timestamps and quality codes. Use this for shift reports, compliance documentation, or troubleshooting equipment issues that happened hours or days ago.&lt;/p&gt;
&lt;p&gt;You&#39;ve now mastered the advanced features that make OPC UA essential for industrial systems. With subscriptions, you&#39;re monitoring values in real-time without wasting bandwidth. With events and alarms, you&#39;re capturing critical alerts the moment they happen. With method calls, you&#39;re executing complex operations with a single command. And with historical access, you have the data trail needed for analysis and compliance.&lt;/p&gt;
&lt;h2 id=&quot;scale-your-opc-ua-implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/advanced-opcua-real-time-subscriptions-alarms-historical-data/#scale-your-opc-ua-implementation&quot;&gt;Scale Your OPC UA Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing OPC UA flows across multiple sites? FlowFuse helps teams deploy Node-RED to hundreds of edge devices with one click, monitor everything from a central dashboard, and roll back instantly if something goes wrong. Built-in team collaboration, audit logs, and enterprise security keep your industrial data safe.&lt;/p&gt;
&lt;p&gt;Following our managed MQTT broker, we&#39;ve now added database services built right into the platform, plus new AI features that make building flows faster than ever.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started free&lt;/a&gt; and scale and manage your Node-RED deployments today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/</id>
        <title>FlowFuse&#39;s New Database: The Easiest Way to Store Industrial IoT Data</title>
        <summary>A step-by-step guide to storing, querying, and managing industrial data without leaving your FlowFuse project.</summary>
        <updated>2025-08-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse recently introduced a &lt;a href=&quot;https://flowfuse.com/handbook/engineering/releases/#beta-release&quot;&gt;beta release&lt;/a&gt; built-in database service to their platform, making it easier than ever to store Industrial IoT data. In a typical setup, you would need to provision a database, manage connection strings and credentials, configure nodes, and handle security settings. The goal of this new feature is to simplify or even eliminate those steps entirely. In this article, you will learn how it works and how to get started.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Tables is available for Enterprise users. If you do not have an Enterprise FlowFuse account and are interested in trying it out, &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact us&lt;/a&gt; to get started.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-enable-the-database-in-your-project&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#step-1%3A-enable-the-database-in-your-project&quot;&gt;Step 1: Enable the Database in Your Project&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the database feature is active on your account, the first step is to create a database instance for your team to use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to your FlowFuse platform.&lt;/li&gt;
&lt;li&gt;In the navigation menu on the left, select the Tables option.&lt;/li&gt;
&lt;li&gt;On the next screen, you will be prompted to &amp;quot;Choose which Database you&#39;d like to get started with.&amp;quot;&lt;/li&gt;
&lt;li&gt;Currently, only Managed PostgreSQL is available. Click on Managed PostgreSQL to proceed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Tables&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Tables&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After you make your selection, FlowFuse will begin provisioning your dedicated database in the background. This process typically takes only a few moments.&lt;/p&gt;
&lt;p&gt;Once the provisioning is complete, you will see two tabs in the Tables section:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explorer&lt;/strong&gt; – Allows you to manage your tables through the user interface. You can create tables, add columns, and view stored data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Tables: Explorer Tab&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables-explorer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Tables: Explorer Tab&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Credentials&lt;/strong&gt; – Provides the database connection details such as host, port, username, and password. These credentials allow you to access the FlowFuse-managed database from outside FlowFuse as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Tables: Credentials Tab&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables-credentials.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Tables: Credentials Tab&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-create-your-first-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#step-2%3A-create-your-first-table&quot;&gt;Step 2: Create Your First Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With your database instance provisioned, you can now create a table to start storing data.&lt;/p&gt;
&lt;p&gt;FlowFuse offers two ways to create a table:&lt;/p&gt;
&lt;h4 id=&quot;option-1%3A-using-the-table-explorer-(ui)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#option-1%3A-using-the-table-explorer-(ui)&quot;&gt;Option 1: Using the Table Explorer (UI)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Navigate to the Explorer tab under the Tables section.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;A form will slide in from the right side of the screen.&lt;/li&gt;
&lt;li&gt;In the first input field, enter the name of your table.&lt;/li&gt;
&lt;li&gt;Click Add New Column to start defining the structure of your table:
&lt;ul&gt;
&lt;li&gt;Column Name: Enter the name of the column.&lt;/li&gt;
&lt;li&gt;Type: Select the appropriate data type (e.g., text, bigint, boolean).&lt;/li&gt;
&lt;li&gt;Default: Check this if you want to set a default value for the column and Once checked, enter the default value in the input field that appears next.&lt;/li&gt;
&lt;li&gt;Nullable: Check this if the column can contain empty (null) values.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Interface for creating FlowFuse tables&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/create-table.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Interface for creating FlowFuse tables&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click Save once your columns are defined.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;option-2%3A-using-sql-via-the-query-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#option-2%3A-using-sql-via-the-query-node&quot;&gt;Option 2: Using SQL via the Query Node&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you prefer writing raw SQL or need more control over your table structure, you can use the Query node in Node-RED.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to your FlowFuse instance where you plan to build the flow and use this table.&lt;/li&gt;
&lt;li&gt;Once you&#39;re in the Node-RED editor, look at the left-side node palette. You will find the Query node under the FlowFuse category.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Query Node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/query-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Query Node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag the Query node into your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;The Query node uses standard SQL syntax and is pre-configured to connect to your FlowFuse-managed database automatically — you do not need to manually enter any database credentials when working inside a FlowFuse Node-RED instance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Double-click the Query node and write your SQL command in the Query field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note: Table names and column names are case-sensitive in SQL when using certain databases like PostgreSQL. To avoid unexpected errors, it is recommended to wrap them in double quotes in your queries.:&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-181&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-181&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;maintenance_tasks&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SERIAL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;assigned_to&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;due_date&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pending&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;in_progress&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;completed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;priority&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;priority&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;low&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;medium&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;high&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-181&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;If you want to send the SQL query dynamically at runtime, you can pass it through &lt;code&gt;msg.query&lt;/code&gt; instead of hardcoding it in the node configuration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Add an Inject node to trigger the query and optionally connect a Debug node to see the output.&lt;/li&gt;
&lt;li&gt;Deploy and click the inject button to create the table.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-3%3A-performing-operations-with-your-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#step-3%3A-performing-operations-with-your-table&quot;&gt;Step 3: Performing Operations with Your Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your table is ready, you can start interacting with it using the &lt;strong&gt;Query&lt;/strong&gt; node. This node allows you to run SQL queries directly—whether it is inserting new data, retrieving records, updating rows, or deleting entries. You can perform all standard operations just as you would with the other database nodes. For this demonstration, you will see how to insert data into your table.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For a complete walkthrough of CRUD operations, you can try out the flow provided at the end of this guide.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;inserting-a-new-record&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#inserting-a-new-record&quot;&gt;Inserting a New Record&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In your Node-RED editor, drag a &lt;strong&gt;Query&lt;/strong&gt; node from the FlowFuse category.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;Inject&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Change node and place it between the Inject and &lt;strong&gt;Query&lt;/strong&gt; nodes. Connect the Inject node to the Change node, and then connect the Change node to the Query node. Double-click the Change node and configure the following properties based on your SQL query requirements. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;msg.title&lt;/code&gt; = &lt;code&gt;&amp;quot;Check motor status&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.description&lt;/code&gt; = &lt;code&gt;&amp;quot;Routine check of motor and related sensors&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.assigned_to&lt;/code&gt; = &lt;code&gt;&amp;quot;technician_1&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.due_date&lt;/code&gt; = &lt;code&gt;&amp;quot;2025-08-10&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.status&lt;/code&gt; = &lt;code&gt;&amp;quot;pending&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.priority&lt;/code&gt; = &lt;code&gt;&amp;quot;medium&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the Query node and write the SQL command in the &lt;strong&gt;Query&lt;/strong&gt; field, For example:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-267&quot;&gt;
  &lt;pre class=&quot;language-mustache&quot;&gt;&lt;code id=&quot;code-267&quot; class=&quot;language-mustache&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;maintenance_tasks&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;assigned_to&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;due_date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;priority&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;assigned_to&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;due_date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-267&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;This node uses the &lt;a href=&quot;https://github.com/janl/mustache.js&quot;&gt;Mustache template system&lt;/a&gt; to dynamically generate queries based on message properties, using the &lt;code&gt;{{{ msg.property }}}&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;While convenient for quick testing and prototyping, this method is &lt;strong&gt;not recommended for production use&lt;/strong&gt;. For better reliability and maintainability, consider using parameterized queries, for that follow &lt;a href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#using-parameters-in-your-queries&quot;&gt;Using Parameters in Your Queries&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Optionally, connect a &lt;strong&gt;Debug&lt;/strong&gt; node to the output of the Query node to inspect the result.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the &lt;strong&gt;Inject&lt;/strong&gt; button to execute the query.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Upon a successful insert operation, the Query node will output a &lt;code&gt;msg.payload&lt;/code&gt; containing an empty array, and a &lt;code&gt;msg.pgsql&lt;/code&gt; object that includes the executed command and a &lt;code&gt;rowCount&lt;/code&gt; indicating the number of rows affected.&lt;/p&gt;
&lt;p&gt;For update or delete operations, the behavior is the same. For select operations, the &lt;code&gt;msg.payload&lt;/code&gt; will contain an array of the returned rows.&lt;/p&gt;
&lt;h3 id=&quot;using-parameters-in-your-queries&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#using-parameters-in-your-queries&quot;&gt;Using Parameters in Your Queries&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, placing Mustache-style strings directly into SQL queries is not considered a best practice. Instead, you should use parameterized queries to keep your queries cleaner, more reliable, and easier to maintain while following best practices.&lt;/p&gt;
&lt;p&gt;The FlowFuse Query node supports both &lt;strong&gt;numbered parameters&lt;/strong&gt; and &lt;strong&gt;named parameters&lt;/strong&gt;, making your SQL queries more flexible, secure, and reusable.&lt;/p&gt;
&lt;h4 id=&quot;option-1%3A-numbered-parameters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#option-1%3A-numbered-parameters&quot;&gt;Option 1: Numbered Parameters&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Numbered parameters let you define placeholders in the SQL string and then pass actual values through &lt;code&gt;msg.params&lt;/code&gt; as an array.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node and set properties based on your SQL command requirements. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.priority&lt;/code&gt; to &#39;high&#39;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.status&lt;/code&gt; to &#39;pending&#39;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Change&lt;/strong&gt; node and set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;[msg.payload.priority, msg.payload.status]&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Query&lt;/strong&gt; node and write an SQL query with numbered parameters. For example:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-343&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-343&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;maintenance_tasks&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;priority&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-343&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Optionally, add a &lt;strong&gt;Debug&lt;/strong&gt; node to view the output.&lt;/li&gt;
&lt;li&gt;Connect the Inject node to the Change node that sets the payload values, then connect it to another Change node that sets the query parameters. Next, connect it to the Query node, and finally connect the Query node to the Debug node.&lt;/li&gt;
&lt;li&gt;Deploy the flow and trigger the Inject node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This query will retrieve rows where &lt;code&gt;priority&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; match the specified values. When you click the Inject node, the actual values from &lt;code&gt;msg.params&lt;/code&gt; will be passed into the placeholders &lt;code&gt;$1&lt;/code&gt; and &lt;code&gt;$2&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;option-2%3A-named-parameters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#option-2%3A-named-parameters&quot;&gt;Option 2: Named Parameters&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Named parameters allow you to reference values by name using a dollar prefix (e.g., &lt;code&gt;$status&lt;/code&gt;) in your SQL query. The actual values are passed using &lt;code&gt;msg.queryParameters&lt;/code&gt; as an object.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node and set properties based on your SQL command requirements. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.id&lt;/code&gt; to 1&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.status&lt;/code&gt; to &amp;quot;in_progress&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add another &lt;strong&gt;Change&lt;/strong&gt; node and set &lt;code&gt;msg.queryParameters&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;. Then add the following rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.queryParameters.id&lt;/code&gt; to &lt;code&gt;msg.payload.id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.queryParameters.status&lt;/code&gt; to &lt;code&gt;msg.payload.status&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Query&lt;/strong&gt; node and write the SQL query using named parameters. For example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-414&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-414&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;maintenance_tasks&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $&lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-414&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, add a &lt;strong&gt;Debug&lt;/strong&gt; node to view the output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject node to the Change node that sets the payload values, then connect it to another Change node that sets the query parameters. Next, connect it to the Query node, and finally connect the Query node to the Debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the &lt;strong&gt;Inject&lt;/strong&gt; button to trigger the update.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When the flow runs, the values in &lt;code&gt;msg.queryParameters&lt;/code&gt; will replace &lt;code&gt;$status&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt; in the SQL statement, ensuring that your queries are dynamic, readable, and secure.&lt;/p&gt;
&lt;p&gt;The Node-RED flow provided below demonstrates a complete set of database interactions. It covers table creation, all standard CRUD (Create, Read, Update, Delete) operations, and includes examples of how to use both numbered and named parameters.&lt;/p&gt;
&lt;div id=&quot;nr-flow-242&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow242 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;1b32d4c878aae3be&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;891c7f50df99de42&#92;&quot;,&#92;&quot;6b0630c1101be59c&#92;&quot;,&#92;&quot;35eda0b6c690e85f&#92;&quot;,&#92;&quot;d638990b04e75f73&#92;&quot;,&#92;&quot;0e0bdc881d4ff5e9&#92;&quot;,&#92;&quot;8f66f27f4fe5a3b1&#92;&quot;,&#92;&quot;5c2da859792c16fa&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:239,&#92;&quot;w&#92;&quot;:532,&#92;&quot;h&#92;&quot;:222},{&#92;&quot;id&#92;&quot;:&#92;&quot;891c7f50df99de42&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b0630c1101be59c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b0630c1101be59c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;CREATE TABLE &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot; (&#92;&#92;n  &#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot; SERIAL PRIMARY KEY,&#92;&#92;n  &#92;&#92;&#92;&quot;title&#92;&#92;&#92;&quot; TEXT NOT NULL,&#92;&#92;n  &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot; TEXT,&#92;&#92;n  &#92;&#92;&#92;&quot;assigned_to&#92;&#92;&#92;&quot; TEXT NOT NULL,&#92;&#92;n  &#92;&#92;&#92;&quot;due_date&#92;&#92;&#92;&quot; DATE NOT NULL,&#92;&#92;n  &#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot; TEXT NOT NULL CHECK (&#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot; IN (&#39;pending&#39;, &#39;in_progress&#39;, &#39;completed&#39;)),&#92;&#92;n  &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot; TEXT NOT NULL CHECK (&#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot; IN (&#39;low&#39;, &#39;medium&#39;, &#39;high&#39;))&#92;&#92;n);&#92;&#92;n&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;35eda0b6c690e85f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;35eda0b6c690e85f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d638990b04e75f73&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Hardcode query within node&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e0bdc881d4ff5e9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dynamically passing query&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8f66f27f4fe5a3b1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;query&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;SELECT * FROM &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot;;&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5c2da859792c16fa&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5c2da859792c16fa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;59e4b997235b486f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SELECT&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1b32d4c878aae3be&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CRUD with Named Parameters&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;a70b79e2d1963518&#92;&quot;,&#92;&quot;8a617977438aedd1&#92;&quot;,&#92;&quot;e725fca338bfc763&#92;&quot;,&#92;&quot;ef5cde3b2e4ae6e5&#92;&quot;,&#92;&quot;ae071cf83947c204&#92;&quot;,&#92;&quot;26de341301b5378b&#92;&quot;,&#92;&quot;d1c2458ddef51e8f&#92;&quot;,&#92;&quot;eb407128caea1c2f&#92;&quot;,&#92;&quot;0b192c85faaee996&#92;&quot;,&#92;&quot;8db1c228e1b464fd&#92;&quot;,&#92;&quot;0ad1449ee792b623&#92;&quot;,&#92;&quot;9a81c88433626bf7&#92;&quot;,&#92;&quot;67ad3eddd7920547&#92;&quot;,&#92;&quot;7b5e3e5014ba62cb&#92;&quot;,&#92;&quot;028bd98bdcf55a8a&#92;&quot;,&#92;&quot;d12e44a1eefb3f6e&#92;&quot;,&#92;&quot;7b7c3b3586c57b6d&#92;&quot;,&#92;&quot;a3f58edc29712b75&#92;&quot;,&#92;&quot;e5a71b865a80248c&#92;&quot;,&#92;&quot;d6cbc55c66a02e36&#92;&quot;,&#92;&quot;6bab0e344178ed4a&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:479,&#92;&quot;w&#92;&quot;:912,&#92;&quot;h&#92;&quot;:262},{&#92;&quot;id&#92;&quot;:&#92;&quot;a70b79e2d1963518&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b5e3e5014ba62cb&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8a617977438aedd1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;INSERT INTO &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot; (&#92;&#92;n  &#92;&#92;&#92;&quot;title&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;assigned_to&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;due_date&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot;&#92;&#92;n) VALUES (&#92;&#92;n  $title,&#92;&#92;n  $description,&#92;&#92;n  $assigned_to,&#92;&#92;n  $due_date,&#92;&#92;n  $status,&#92;&#92;n  $priority&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e725fca338bfc763&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e725fca338bfc763&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef5cde3b2e4ae6e5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;UPDATE &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot;&#92;&#92;nSET &#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot; = $status&#92;&#92;nWHERE &#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot; = $id;&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;26de341301b5378b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ae071cf83947c204&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.id&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.status&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.status&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ef5cde3b2e4ae6e5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;26de341301b5378b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d1c2458ddef51e8f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;028bd98bdcf55a8a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;eb407128caea1c2f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SELECT&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;SELECT * FROM &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot;&#92;&#92;nWHERE &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot; = $priority AND &#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot; = &#39;pending&#39;;&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8db1c228e1b464fd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0b192c85faaee996&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.priority&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.priority&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;eb407128caea1c2f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8db1c228e1b464fd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0ad1449ee792b623&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SELECT&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9a81c88433626bf7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9a81c88433626bf7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.priority&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;high&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0b192c85faaee996&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;67ad3eddd7920547&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.title&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.title&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.description&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.description&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.assigned_to&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.assigned_to&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.due_date&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.due_date&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.status&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.status&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.priority&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.priority&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8a617977438aedd1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b5e3e5014ba62cb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.title&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Replace air conditioner filter&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.description&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;The air filter in the main office needs to be replaced to maintain air quality.&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.assigned_to&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;jdoe&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.due_date&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;2025-08-15&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.status&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;pending&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.priority&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;high&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;67ad3eddd7920547&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;028bd98bdcf55a8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.status&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;in_progress&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ae071cf83947c204&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d12e44a1eefb3f6e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Delete&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;DELETE FROM &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot;&#92;&#92;nWHERE &#92;&#92;&#92;&quot;id&#92;&#92;&#92;&quot; = $id;&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a3f58edc29712b75&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b7c3b3586c57b6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;queryParameters.id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.id&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d12e44a1eefb3f6e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a3f58edc29712b75&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e5a71b865a80248c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;DELETE&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d6cbc55c66a02e36&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d6cbc55c66a02e36&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b7c3b3586c57b6d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6bab0e344178ed4a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;98f1c134581e0cdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Named Parameters&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example flow: numbered parameters&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;c68690d2546f65cf&#92;&quot;,&#92;&quot;eb65c1a44ae25dd7&#92;&quot;,&#92;&quot;f38fed90c8e1f2f6&#92;&quot;,&#92;&quot;2b9e486cca212636&#92;&quot;,&#92;&quot;f492d66aa25e20aa&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:759,&#92;&quot;w&#92;&quot;:672,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;c68690d2546f65cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Numbered Parameters&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;eb65c1a44ae25dd7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;function 3&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.params = {}&#92;&#92;nmsg.params = [msg.payload.title, msg.payload.description, msg.payload.assigned_to, msg.payload.due_date, msg.payload.status, msg.payload.priority]&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2b9e486cca212636&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f38fed90c8e1f2f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;title&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Replace air conditioner filter&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;The air filter in the main office needs to be replaced to maintain air quality.&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;assigned_to&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;jdoe&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;due_date&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;2025-08-15&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;pending&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;high&#92;&#92;&#92;&quot;}&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;eb65c1a44ae25dd7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2b9e486cca212636&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tables-query&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;INSERT INTO &#92;&#92;&#92;&quot;maintenance_tasks&#92;&#92;&#92;&quot; (&#92;&#92;n  &#92;&#92;&#92;&quot;title&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;assigned_to&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;due_date&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;status&#92;&#92;&#92;&quot;,&#92;&#92;n  &#92;&#92;&#92;&quot;priority&#92;&#92;&#92;&quot;&#92;&#92;n) VALUES (&#92;&#92;n  $1, $2, $3, $4, $5, $6&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;split&#92;&quot;:false,&#92;&quot;rowsPerMsg&#92;&quot;:1,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f492d66aa25e20aa&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f492d66aa25e20aa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa9da3f45f949067&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;7d584a17652f6545&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Result&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53b4963ef005eadf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;global-config&#92;&quot;,&#92;&quot;env&#92;&quot;:[],&#92;&quot;modules&#92;&quot;:{&#92;&quot;@flowfuse/nr-tables-nodes&#92;&quot;:&#92;&quot;0.1.0&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow242.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-242&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/getting-started-with-flowfuse-tables/#wrapping-up&quot;&gt;Wrapping Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You&#39;ve now learned how to leverage FlowFuse Tables to simplify database management in your Industrial IoT projects. Here&#39;s what you&#39;ve accomplished:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Provisioned&lt;/strong&gt; a managed PostgreSQL database with zero configuration overhead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Created tables&lt;/strong&gt; using both the intuitive UI and flexible SQL approach&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Executed queries&lt;/strong&gt; safely using parameterized queries for production-ready flows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performed CRUD operations&lt;/strong&gt; with the versatile Query node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The combination of FlowFuse Tables and the built-in &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;MQTT broker&lt;/a&gt; eliminates the complexity of managing external database and messaging infrastructure, letting you focus on building automation solutions rather than wrestling with DevOps.&lt;/p&gt;
&lt;p&gt;Ready to see how FlowFuse Tables can accelerate your next industrial project? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo with our team&lt;/a&gt; to explore the full platform capabilities.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next up: We&#39;ll dive into Query node advanced features including backpressure handling and streaming large datasets—essential techniques for high-volume industrial applications.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/</id>
        <title>The Evolution of Business Automation: Why Pricing Models Matter</title>
        <summary>The importance of a predictable pricing model in workflow automation</summary>
        <updated>2025-08-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/"/>
        <author><name>Pablo Filomeno</name></author>
        <content type="html">&lt;p&gt;The automation landscape is evolving rapidly, and recent industry developments have sparked important conversations about how businesses should evaluate their automation platforms. N8N’s recent shift from workflow-based to execution-based pricing — positioned as removing limits — has received mixed reactions from the community, with many growing businesses finding the reality more complex. As pricing models change across the industry, now is the perfect time to reflect on what truly matters when choosing the right automation solution for your needs.&lt;/p&gt;
&lt;h2 id=&quot;the-current-state-of-automation-pricing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#the-current-state-of-automation-pricing&quot;&gt;The Current State of Automation Pricing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many automation platforms are rethinking their pricing structures, moving from workflow-based models to execution-based billing. While this approach aims to provide more flexibility, it can create new challenges for businesses trying to predict costs and plan their automation strategies.&lt;/p&gt;
&lt;p&gt;Execution-based pricing means each step or run of your workflow consumes credits or counts toward your usage limits. What initially appears straightforward can become complex when scaling automation across teams and departments.&lt;/p&gt;
&lt;h2 id=&quot;what-business-users-really-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#what-business-users-really-need&quot;&gt;What Business Users Really Need&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Based on conversations we&#39;re seeing in automation communities, business users are looking for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost predictability&lt;/strong&gt;: The ability to forecast automation expenses as operations grow&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability confidence&lt;/strong&gt;: Knowing their platform can handle increased complexity without surprises&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team collaboration&lt;/strong&gt;: Tools that support multiple users working together effectively&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise readiness&lt;/strong&gt;: Solutions built to handle business-critical operations from the start&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flowfuse%3A-built-for-business-automation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#flowfuse%3A-built-for-business-automation&quot;&gt;FlowFuse: Built for Business Automation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse takes a different approach to business automation, focusing on what enterprises actually need rather than trying to retrofit consumer tools for business use.&lt;/p&gt;
&lt;h3 id=&quot;industrial-grade-foundation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#industrial-grade-foundation&quot;&gt;Industrial-Grade Foundation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse is designed as an Industrial Application Platform that empowers teams to build, deploy and manage applications that optimize industrial operations. This isn&#39;t an add-on feature—it&#39;s fundamental to how we approach automation.&lt;/p&gt;
&lt;h3 id=&quot;the-power-of-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#the-power-of-node-red&quot;&gt;The Power of Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the heart of FlowFuse is Node-RED, the free and truly Open Source low-code programming tool of choice for industrial applications. With over 5,000 community-contributed nodes, Node-RED enables engineers to collect, transform, and integrate data through visualized dashboards. It&#39;s been proven in everything from home automation to massive industrial deployments.&lt;/p&gt;
&lt;h3 id=&quot;transparent-business-model&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#transparent-business-model&quot;&gt;Transparent Business Model&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rather than complex execution counting, FlowFuse focuses on delivering reliable automation that scales with your business needs. Our approach eliminates the guesswork and lets you focus on building solutions rather than calculating usage; costs scale with how many Node-RED runtimes you need to manage.&lt;/p&gt;
&lt;h2 id=&quot;key-advantages-of-the-flowfuse-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#key-advantages-of-the-flowfuse-approach&quot;&gt;Key Advantages of the FlowFuse Approach&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enterprise-First Design:&lt;/strong&gt;
FlowFuse is built specifically for mission-critical business applications where reliability isn&#39;t optional.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;True Team Collaboration:&lt;/strong&gt;
FlowFuse enables organizations to reliably deliver Node-RED applications in a continuous, collaborative and secure manner, supporting team-based development from the ground up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flexible Deployment Options:&lt;/strong&gt;
Whether you need cloud, on-premises, or hybrid deployment, FlowFuse adapts to your infrastructure requirements without artificial constraints.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mature, Battle-Tested Ecosystem:&lt;/strong&gt;
Built on Node-RED&#39;s proven foundation, FlowFuse leverages years of community development and real-world industrial deployment experience.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;evaluating-your-automation-strategy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#evaluating-your-automation-strategy&quot;&gt;Evaluating Your Automation Strategy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the automation landscape evolves, consider these key factors when choosing or re-evaluating your platform:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost Transparency&lt;/strong&gt;: Can you clearly understand and predict your automation costs as you scale?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Business Focus&lt;/strong&gt;: Is your platform designed for enterprise requirements, or adapted from simpler use cases?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Team Support&lt;/strong&gt;: Does your solution enable effective collaboration across your organization?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-term Stability&lt;/strong&gt;: Is your chosen platform built to handle the complexity and scale of business operations?&lt;/p&gt;
&lt;h2 id=&quot;the-flowfuse-advantage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#the-flowfuse-advantage&quot;&gt;The FlowFuse Advantage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse stands out because we&#39;ve built our platform specifically for business automation challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Predictable, business-friendly pricing&lt;/strong&gt; that grows with your needs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Industrial-grade reliability&lt;/strong&gt; for mission-critical applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise security and compliance&lt;/strong&gt; built in from day one&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Professional support&lt;/strong&gt; that understands business requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ready-to-experience-the-difference%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/08/flowfuse-why-pricing-matters/#ready-to-experience-the-difference%3F&quot;&gt;Ready to Experience the Difference?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While other platforms adapt consumer tools for business use, FlowFuse was designed from the ground up for enterprise automation needs.&lt;/p&gt;
&lt;p&gt;A free trial is available for FlowFuse Cloud, and you can also run FlowFuse locally, docker-based, or in Kubernetes.&lt;/p&gt;
&lt;p&gt;Experience automation without the complexity of execution counting or artificial limitations. Discover how FlowFuse can support your business&#39;s growth with transparent, scalable solutions.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Ready to get started? &lt;a href=&quot;https://flowfuse.com/&quot;&gt;Explore FlowFuse today&lt;/a&gt; and see why businesses choose purpose-built automation platforms.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/</id>
        <title>FlowFuse 2.20: AI-Assisted Node-RED &amp; New Database Service</title>
        <summary>Introducing FlowFuse Tables for data storage, Tables nodes for database querying, Smart Suggestions in the Node-RED editor, More Powerful Instances, Retrieval Augmented Generation Blueprint for building intelligent applications, and a redesigned Applications page for better workspace management.</summary>
        <updated>2025-07-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release represents a major leap forward in FlowFuse&#39;s data management and AI capabilities, introducing our new FlowFuse Tables database feature, along with enhanced AI assistance features and a streamlined user interface. These improvements make FlowFuse a complete solution for building industrial applications, even while reducing development time.&lt;/p&gt;
&lt;h2 id=&quot;introducing%3A-flowfuse-tables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#introducing%3A-flowfuse-tables&quot;&gt;Introducing: FlowFuse Tables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot of the new &amp;quot;Tables&amp;quot; view, now available in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables-ui-screenshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A screenshot of the new &amp;quot;Tables&amp;quot; view, now available in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse Tables is our brand new database offering that provides a simple way to store your data, all within the FlowFuse ecosystem. This comprehensive database offering comes with FlowFuse&#39;s enterprise-grade security and unlocks the ability to seamlessly build critical systems like MES and ERP.&lt;/p&gt;
&lt;p&gt;FlowFuse Tables eliminates the complexity of setting up and managing separate database infrastructure, allowing you to focus on building applications that drive operational efficiency.&lt;/p&gt;
&lt;p&gt;FlowFuse Tables is available now for all Enterprise users running on FlowFuse Cloud.&lt;/p&gt;
&lt;h3 id=&quot;new-node%3A-query&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#new-node%3A-query&quot;&gt;New Node: Query&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A flow in Node-RED that uses the new FlowFuse &amp;quot;Query&amp;quot; node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tables-query-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A flow in Node-RED that uses the new FlowFuse &amp;quot;Query&amp;quot; node&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alongside the new Tables offering, we have shipped a new node that you can find in your Node-RED Editor - &amp;quot;Query&amp;quot;. This will automatically connect to any associated database you have with your team, saving you time in manually configuring nodes and credentials, giving you more time to just focus on the fun of building your flows, and making it really easy to start storing and querying your data.&lt;/p&gt;
&lt;h2 id=&quot;ai-assisted-node-red-with-smart-suggestions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#ai-assisted-node-red-with-smart-suggestions&quot;&gt;AI-Assisted Node-RED with Smart Suggestions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;GIF of Smart Suggestions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/smart-suggestion.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;GIF of Smart Suggestions in Action&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Development in Node-RED is now even faster with Smart Suggestions, an agent that runs in-browser and offers intelligent flow completion for next-node recommendations. With Smart Suggestions, as you place a node, the agent will automatically calculate the most likely next node to place, and will offer suggestions for the node&#39;s configuration. It present up to 5 options, so even if the first suggestion isn&#39;t correct, it&#39;s very likely that the correct choice is only a quick keyboard shortcut away.&lt;/p&gt;
&lt;p&gt;This work extends the functionality of the in-built FlowFuse Expert and it&#39;s MCP server that runs behind the Node-RED Editor to provide power additional development enhancements.&lt;/p&gt;
&lt;h2 id=&quot;new-blueprint%3A-agentic-ai-with-retrieval-augmented-generation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#new-blueprint%3A-agentic-ai-with-retrieval-augmented-generation&quot;&gt;New Blueprint: Agentic AI with Retrieval Augmented Generation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/Blueprint+-+Open+AI+RAG.mp4&quot; controls=&quot;&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The new RAG (Retrieval Augmented Generation) Blueprint enables you to train your own LLM agents, combining your own data with natural language capabilities.&lt;/p&gt;
&lt;p&gt;This Blueprint provides two flows: one that adds text into Node-RED&#39;s flow context store and uses it to train an OpenAI agent, so you can query the content of the flow directly; and one flow that scrapes websites to train an OpenAI agent so that content can be queried and used as well.&lt;/p&gt;
&lt;p&gt;The RAG Blueprint makes it easy to create intelligent agents that leverage your organizational knowledge without requiring deep AI expertise. &lt;a href=&quot;https://flowfuse.com/blueprints/ai/rag-chat-agent/&quot;&gt;Try it out for yourself here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;refined-applications-page&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#refined-applications-page&quot;&gt;Refined Applications Page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of New Applications Page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/applications-redesign.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Redesigned Applications Page&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With the new FlowFuse Home page in place, we have greatly streamlined the Applications page. The new structure includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Streamlined Navigation&lt;/strong&gt;: Applications now appear under Instances in the navigation hierarchy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Cognitive Load&lt;/strong&gt;: Eliminated the overwhelming number of buttons and links in the previous design&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus on Important Information&lt;/strong&gt;: The newly refined design focusses on giving you a clear overview of the status of your Hosted and Remote Instances, split by Application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance Optimizations&lt;/strong&gt;: The above has also lead to faster page loading and improved responsiveness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This redesign creates a more intuitive workflow that aligns with how teams actually use FlowFuse, reducing clicks and improving productivity.&lt;/p&gt;
&lt;h2 id=&quot;more-powerful-%22small%22-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#more-powerful-%22small%22-instances&quot;&gt;More Powerful &amp;quot;Small&amp;quot; Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Based on user feedback and our own review of instance performance, we have increased the CPU and memory of all &amp;quot;small&amp;quot; Node-RED instances running on FlowFuse. This will have the immediate benefit of preventing slowdowns and loading issues for all Starter and Team customers.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our development roadmap continues to focus on AI integration and enterprise data management. Upcoming releases will expand FlowFuse Tables with additional database types and analytics capabilities, while our FlowFuse Expert will gain more sophisticated workflow automation features.&lt;/p&gt;
&lt;p&gt;We&#39;re also working on enhanced Blueprint offerings and deeper integration between our AI capabilities and industrial data sources, with several exciting announcements planned for the coming months!&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.20 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.20.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-20/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/</id>
        <title>FlowFuse Expert: Let Your Engineers Build Automation, Not Write Code</title>
        <summary>Make Node-RED do more without writing code.</summary>
        <updated>2025-07-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Every manufacturing engineer knows this scenario: Node-RED&#39;s visual programming handles most of your automation needs brilliantly. Connect to PLCs, route data, trigger actions—all with drag-and-drop simplicity, but then you hit the wall. Your machine outputs data in a proprietary format. You need a custom dashboard widget that doesn&#39;t exist. You&#39;re manually creating test data for hours, or you&#39;re trying to understand a complex flow built by someone who left last year.&lt;/p&gt;
&lt;p&gt;These bespoke tasks can often demand coding skills—JavaScript for parsing data, Vue.js for custom widgets, CSS for styling. Skills your automation engineers might not have. Skills that pull them away from what the engineers do best: optimizing production.&lt;/p&gt;
&lt;p&gt;FlowFuse Expert changes this dynamic completely. Describe what you need in plain English, then, get working code instantly. No more hours lost to syntax errors or Stack Overflow searches. Your engineers can focus on their own expertise, and FlowFuse Expert fills in the gaps. Let&#39;s look at how manufacturing teams can use it to solve real problems.&lt;/p&gt;
&lt;h2 id=&quot;parsing-machine-data-without-the-javascript-struggle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/#parsing-machine-data-without-the-javascript-struggle&quot;&gt;Parsing Machine Data Without the JavaScript Struggle&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While Node-RED&#39;s low-code nodes cover most scenarios, every production line has unique quirks. Complex data parsing, multi-step calculations, proprietary protocols—these can all be accomplished in Node-RED by writing your own JavaScript. Engineers, who should be focussed on optimizing processes, end up out of their comfort zone, searching regex patterns and debugging syntax errors.&lt;/p&gt;
&lt;p&gt;Consider this output from a CNC machine that&#39;s been reliable for 15 years:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-18&quot;&gt;
  &lt;pre class=&quot;language-text&quot;&gt;&lt;code id=&quot;code-18&quot; class=&quot;language-text&quot;&gt;-- CYCLE END REPORT --&lt;br /&gt;ID: M-45B / PART: XF-201&lt;br /&gt;TIMESTAMP: 2025-07-09T14:22:01Z&lt;br /&gt;SERIAL: 2025-0001547&lt;br /&gt;OPERATOR: JONES, M&lt;br /&gt;STATS ---&lt;br /&gt;PART_COUNT: 481&lt;br /&gt;CYCLE_TIME: 114.72&lt;br /&gt;MAX_TEMP: 85.3&lt;br /&gt;TOOL_WEAR_IDX: 0.73&lt;br /&gt;COOLANT_LEVEL: OK&lt;br /&gt;ALERTS: NONE&lt;br /&gt;-- END --&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-18&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The traditional approach means spending 30-50 minutes writing regex patterns, handling edge cases, and testing thoroughly. Your engineer needs to remember JavaScript string methods, debug regex syntax, and account for variations in the output format.&lt;/p&gt;
&lt;p&gt;With FlowFuse Expert, the process changes completely. Your engineer opens a function node, clicks the FlowFuse Expert button, and types:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Parse this CNC report format. Extract PART_COUNT as integer, CYCLE_TIME as float, TOOL_WEAR_IDX as float, OPERATOR name, and ALERTS. Return as JSON.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The engineer reviews the code, tests it with their data, and moves on to solving actual manufacturing problems instead of wrestling with JavaScript syntax.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert generating a Node-RED function node to extract data from a CNC text report.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/function-ai.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert generating a Node-RED function node to extract data from a CNC text report.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;creating-test-data-in-seconds%2C-not-hours&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/#creating-test-data-in-seconds%2C-not-hours&quot;&gt;Creating Test Data in Seconds, Not Hours&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before connecting to live equipment, you need test data that looks real. Making it by hand is tedious and wastes lots of time.&lt;/p&gt;
&lt;p&gt;With FlowFuse Expert, just ask:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Generate 20 machine records with machine_id, production_count, efficiency_percentage, downtime_minutes, and last_maintenance_date. Show realistic variations.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s as simple as that.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert generating test JSON data with multiple machine records including production counts and efficiency metrics&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/json-ai.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert creating realistic test data for manufacturing dashboards—complete with machine IDs, production metrics, and maintenance dates.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-custom-dashboards-without-web-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/#building-custom-dashboards-without-web-development&quot;&gt;Building Custom Dashboards Without Web Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; widgets cover most UI needs, but manufacturing can often demand more. Custom visualizations for specific KPIs can be build in Dashboard with the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template&quot;&gt;&amp;quot;Template&amp;quot;&lt;/a&gt; node, where developers can write their own Vue.js templates.&lt;/p&gt;
&lt;p&gt;Developing custom components to match your HMI design standards takes CSS expertise. Whether you&#39;re building new widgets or styling existing ones, you&#39;re suddenly in web development territory—far from where most automation engineers want to be.&lt;/p&gt;
&lt;p&gt;Take a &lt;a href=&quot;https://en.wikipedia.org/wiki/Pareto_chart&quot;&gt;Pareto Chart&lt;/a&gt; for defect analysis as an example—essential for quality teams but not available as a standard Dashboard widget. Building it requires Vue.js knowledge, Chart.js integration, and responsive design skills.&lt;/p&gt;
&lt;p&gt;With FlowFuse Expert, just describe what you need:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Create a Pareto chart widget showing defect counts as bars with a cumulative percentage line. Include the 80% threshold.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert creating custom dashboard components and styling for manufacturing displays&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-ai.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert building both custom widgets and styling existing components for manufacturing dashboards.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Or consider input boxes for operator data entry that look too modern. Your team prefers the familiar green LCD screens they&#39;ve used for decades, you can ask FlowFuse Expert:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Add CSS that makes the input with classes &#39;calculator&#39; and &#39;text-input&#39; look like an old green LCD calculator screen.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert generating CSS to style input fields with green LCD calculator display appearance&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/css-ai.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert creating CSS that transforms standard input boxes into retro LCD displays with glowing green text.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Whether creating new widgets or styling existing ones, FlowFuse Expert handles the Vue.js and CSS complexity. You describe the outcome—it generates the code.&lt;/p&gt;
&lt;h2 id=&quot;documenting-complex-flows-before-knowledge-walks-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/#documenting-complex-flows-before-knowledge-walks-out&quot;&gt;Documenting Complex Flows Before Knowledge Walks Out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Production flows evolve over years into complex systems. Hundreds of nodes, critical logic buried in functions, intricate routing between tabs. When knowledge walks out the door, new team members can face weeks of detective work trying to understand flows and their colleague&#39;s work.&lt;/p&gt;
&lt;p&gt;FlowFuse Expert&#39;s Flow Explainer solves this. Select any flow or group of nodes, click &amp;quot;Explain,&amp;quot; and get instant documentation. It analyzes connections, reads function code, and generates clear explanations of what everything does and why.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Expert explaining the purpose and behavior of a complex Node-RED flow in plain language.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-expainer-ai.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Expert turning complex flows into clear documentation for easy knowledge transfer.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;start-building-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-ai-assistant-better-node-red-manufacturing/#start-building-today&quot;&gt;Start Building Today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Expert is just one way FlowFuse helps manufacturing teams work faster.&lt;/p&gt;
&lt;p&gt;Teams collaborate on flows in real-time. Version control with snapshots means you can always go back if something breaks. Remote device management handles edge devices across your factory floor. Deploy to one machine or a thousand with a single click. Built-in DevOps pipelines streamline your workflow from development to production.&lt;/p&gt;
&lt;p&gt;For production reliability, high availability keeps systems running 24/7. The integrated MQTT broker handles all your device messaging. Enterprise security includes SSO, multi-factor authentication, role-based access control, and complete audit logs.&lt;/p&gt;
&lt;p&gt;FlowFuse gives you everything you need to build, deploy, and manage Node-RED at scale.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse free →&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/</id>
        <title>Statistical Process Control (SPC): Benefits and Implementation Guide</title>
        <summary>A practical guide to implementing Statistical Process Control with FlowFuse</summary>
        <updated>2025-07-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Leading manufacturers are quietly saving thousands, sometimes millions, of dollars annually with a quality control method that&#39;s been proven since the 1920s. The difference today? Modern tools make it simple to implement.&lt;/p&gt;
&lt;p&gt;Consider this real example: A manufacturer shared on Practical Machinist forum that they process 400,000 parts per year with a 4% scrap rate. That&#39;s 16,000 parts discarded annually. At even a conservative $10 per part, this represents $160,000 in direct losses from a single production line. They accepted this as normal because industry reports confirm 4-5% scrap rates are standard.&lt;/p&gt;
&lt;p&gt;What separates industry leaders from the rest? They refuse to accept &amp;quot;normal&amp;quot; waste. Using Statistical Process Control (SPC), they detect problems as they occur, not after producing defective parts. When a process begins drifting, they receive immediate alerts and correct it before generating scrap.&lt;/p&gt;
&lt;p&gt;This guide shows you exactly how to build a real-time SPC system using FlowFuse. You&#39;ll create a live dashboard that tracks measurements and alerts operators the moment something goes wrong. No statistics degree needed, just practical steps you can implement today.&lt;/p&gt;
&lt;h2 id=&quot;why-traditional-quality-control-falls-short&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#why-traditional-quality-control-falls-short&quot;&gt;Why Traditional Quality Control Falls Short&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most manufacturers still rely on end-of-line inspection. Make parts, check parts, scrap the bad ones. This reactive approach creates three expensive problems:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem 1: You&#39;re always too late&lt;/strong&gt;
When inspection finds a defect, you&#39;ve already invested in material, machine time, labor, and energy. That investment is now scrap. Worse, how many parts did you make between when the problem started and when you caught it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem 2: The borderline parts you miss&lt;/strong&gt;
Not all defects are obvious. Parts that barely pass inspection today might fail in the field tomorrow. These marginal parts slip through because traditional inspection only catches clear failures, not process degradation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem 3: No insight into root causes&lt;/strong&gt;
Finding bad parts tells you nothing about why they&#39;re bad. Was it temperature drift? Tool wear? Material variation? Without process data, you&#39;re guessing at solutions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Proactive Alternative: Statistical Process Control&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SPC flips the entire approach. Instead of checking parts after production, it monitors your process during production. The NIST Engineering Statistics Handbook explains it simply:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The underlying concept of statistical process control is based on a comparison of what is happening today with what happened previously.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When your process starts to drift from its normal behavior, SPC alerts you immediately. You fix the issue before making defective parts, not after.&lt;/p&gt;
&lt;p&gt;Walter Shewhart developed this method at Bell Labs in the 1920s, proving its effectiveness across industries. Today, FlowFuse makes it accessible to any manufacturer, regardless of size or technical expertise.&lt;/p&gt;
&lt;h2 id=&quot;building-your-first-spc-system-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#building-your-first-spc-system-with-flowfuse&quot;&gt;Building Your First SPC System with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s build a real example. This guide shows you how to create a SPC control chart for individual measurements - perfect for monitoring critical dimensions in real-time.&lt;/p&gt;
&lt;p&gt;First, open your FlowFuse Node-RED instance. If you don&#39;t have one yet, you can &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up for a free account&lt;/a&gt; and have an instance running in minutes.&lt;/p&gt;
&lt;h3 id=&quot;what-we&#39;re-building&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#what-we&#39;re-building&quot;&gt;What We&#39;re Building&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A real-time SPC control chart that monitors individual measurements and automatically calculates control limits. Perfect for scenarios where you measure one part at a time - like bearing dimensions on a CNC line. When measurements drift outside the calculated limits, you&#39;ll know instantly.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-get-your-tools-ready&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-1%3A-get-your-tools-ready&quot;&gt;Step 1: Get Your Tools Ready&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we need two nodes for SPC monitoring.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open FlowFuse&#39;s palette manager (hamburger menu → Manage palette)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the Install tab&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Search for and install these nodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-simple-spc&lt;/code&gt; - This is your statistics engine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; - For that slick real-time chart&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Install for each node and wait for completion&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-2%3A-simulate-your-machine-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-2%3A-simulate-your-machine-data&quot;&gt;Step 2: Simulate Your Machine Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In production, you&#39;d connect to your PLC. For now, let&#39;s simulate a bearing measurement around 10mm nominal.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto your canvas. This is your &amp;quot;sensor.&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click it and set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repeat: &lt;code&gt;interval&lt;/code&gt; → &lt;code&gt;2 seconds&lt;/code&gt; (mimics real sensor timing)&lt;/li&gt;
&lt;li&gt;Payload: switch to JSONata mode and enter: &lt;code&gt;$random() * 0.2 + 10&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This generates readings like 10.05, 9.98, 10.11 - realistic variation around 10mm.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-add-the-statistical-brain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-3%3A-add-the-statistical-brain&quot;&gt;Step 3: Add the Statistical Brain&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Find the &lt;strong&gt;spc&lt;/strong&gt; node in your palette (it&#39;ll be under &amp;quot;function&amp;quot; category after install).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag it over and wire your inject node to it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click to configure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control Limit Multiplier: &lt;code&gt;3&lt;/code&gt; (for 3-sigma limits)&lt;/li&gt;
&lt;li&gt;Timer: &lt;code&gt;10&lt;/code&gt; (seconds before alerting out-of-control)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once configured, the node outputs an object like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-165&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-165&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.020214950604476&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;// Current measurement&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.089877376434453&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;// Running average&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;ucl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.344067494423967&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;// Upper control limit&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;lcl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9.835687258444938&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;// Lower control limit&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;outOfControl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;              &lt;span class=&quot;token comment&quot;&gt;// Alert status&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-165&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-4%3A-make-the-data-chart-ready&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-4%3A-make-the-data-chart-ready&quot;&gt;Step 4: Make the Data Chart-Ready&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Charts need data in a specific format. Add a &lt;strong&gt;change&lt;/strong&gt; node between SPC and your chart.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change&lt;/strong&gt; node onto the canvas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wire it between the SPC node and where your chart will go&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click to configure and set one rule: &lt;code&gt;Set msg.payload&lt;/code&gt; to this JSONata expression:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-189&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-189&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;series&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Measurement&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $millis()&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload.value&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;series&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;UCL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $millis()&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload.ucl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;series&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LCL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $millis()&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload.lcl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;series&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Average&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $millis()&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload.avg&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-189&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This creates four lines on your chart, your actual measurements plus the three control lines.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-build-your-control-room-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-5%3A-build-your-control-room-dashboard&quot;&gt;Step 5: Build Your Control Room Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll create the dashboard that displays your SPC control chart. This is what operators will watch to spot problems in real-time.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;chart&lt;/strong&gt; widget from the dashboard section and set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type: &lt;code&gt;Line Chart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;X-axis: &lt;code&gt;HH:mm:ss&lt;/code&gt; (shows time)&lt;/li&gt;
&lt;li&gt;Series: Set to &lt;code&gt;series&lt;/code&gt; (as key)&lt;/li&gt;
&lt;li&gt;X: Set to &lt;code&gt;x&lt;/code&gt; (as key)&lt;/li&gt;
&lt;li&gt;Y: Set to &lt;code&gt;y&lt;/code&gt; (as key)&lt;/li&gt;
&lt;li&gt;Legend: &lt;code&gt;Show&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Label: &amp;quot;SPC Chart: Bearing Diameter (mm)&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node to it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED flow showing SPC monitoring setup with inject node, SPC calculations, data formatting, and dashboard chart configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/spc.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Complete SPC monitoring flow with real-time chart display&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-6%3A-add-the-alert-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-6%3A-add-the-alert-system&quot;&gt;Step 6: Add the Alert System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A chart is nice, but you need immediate alerts. Here&#39;s the clever bit:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;switch&lt;/strong&gt; node connected to your SPC output&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set it to check &lt;code&gt;msg.payload.outOfControl&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create two outputs: true and false&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now add a &lt;strong&gt;text&lt;/strong&gt; nodes from dashboard. Wire it to your switch outputs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the &amp;quot;true&amp;quot; path, set the text to something attention-grabbing using change node:
&lt;code&gt;⚠️ PROCESS OUT OF CONTROL - CHECK MACHINE!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For the &amp;quot;false&amp;quot; path:
&lt;code&gt;✓ Process Stable&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED alert system with switch node: Process stable&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/spc-visual-alert.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED alert system with switch node: Process stable&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-7%3A-test-your-spc-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#step-7%3A-test-your-spc-system&quot;&gt;Step 7: Test Your SPC System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Open your dashboard (switch to the Dashboard 2.0 tab → click Open Dashboard button on the top-right of the right sidebar).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What you&#39;ll see initially:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First 20 measurements: Chart builds up baseline data&lt;/li&gt;
&lt;li&gt;After 20 points: Control limits appear automatically&lt;/li&gt;
&lt;li&gt;Blue line bouncing between red lines: Process is stable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let the system run for a minute to establish your baseline. The control limits aren&#39;t arbitrary - they&#39;re calculated from your actual process data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now test it with a simulated process shift:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Double-click the Inject node&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change the formula to &lt;code&gt;$random() * 0.2 + 10.5&lt;/code&gt; (this shifts the mean up by 0.5mm)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Done to close the node&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy only the modified nodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click the down arrow next to the &lt;strong&gt;Deploy&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Modified Nodes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Deploy&lt;/strong&gt; button&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED deploy menu showing Modified Nodes option for selective deployment&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modifed-nodes-deploy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Deploy menu with Modified Nodes option for updating only changed nodes&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once done You will see the chart detect the change within seconds.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;SPC chart showing process shift with measurements exceeding upper control limit and alert triggered&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/spc-visual-alert2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;SPC chart detecting process shift - measurements above UCL trigger immediate alert&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-226&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow226 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;4082f89605793666&#92;&quot;,&#92;&quot;2ec8351f01f957a4&#92;&quot;,&#92;&quot;c90d67c57d1af3bd&#92;&quot;,&#92;&quot;53ef849a41aee2b3&#92;&quot;,&#92;&quot;d78ff3dbe97a5be9&#92;&quot;,&#92;&quot;98e76616c28ed9ca&#92;&quot;,&#92;&quot;5fd3415ef4c36b6e&#92;&quot;,&#92;&quot;9763632606c2a165&#92;&quot;],&#92;&quot;x&#92;&quot;:214,&#92;&quot;y&#92;&quot;:159,&#92;&quot;w&#92;&quot;:872,&#92;&quot;h&#92;&quot;:162},{&#92;&quot;id&#92;&quot;:&#92;&quot;4082f89605793666&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;$random() * 0.2 + 10.5&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2ec8351f01f957a4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ec8351f01f957a4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;spc&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;limitMultiplier&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;timer&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c90d67c57d1af3bd&#92;&quot;,&#92;&quot;d78ff3dbe97a5be9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c90d67c57d1af3bd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[     {&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Measurement&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;: $millis(), &#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;: payload.value},     {&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;UCL&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;: $millis(), &#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;: payload.ucl},     {&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;LCL&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;: $millis(), &#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;: payload.lcl},     {&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Average&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;: $millis(), &#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;: payload.avg} ]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;53ef849a41aee2b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53ef849a41aee2b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3af21cf2cea638c8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;I-MR Chart: Bearing Diameter (mm)&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;series&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;x&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;xmin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xmax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;y&#92;&quot;,&#92;&quot;yAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bins&#92;&quot;:10,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#a347e1&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;interpolation&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d78ff3dbe97a5be9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload.outOfControl&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;true&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;false&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;98e76616c28ed9ca&#92;&quot;],[&#92;&quot;5fd3415ef4c36b6e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;98e76616c28ed9ca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;⚠️ PROCESS OUT OF CONTROL - CHECK MACHINE!&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9763632606c2a165&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5fd3415ef4c36b6e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;✓ Process Stable&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9763632606c2a165&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9763632606c2a165&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;071524a8fd482116&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;124f531365b82e1c&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3af21cf2cea638c8&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;Visual Alert&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;col-center&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Arial,Arial,Helvetica,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;24&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3af21cf2cea638c8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Group 1&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;735102f229f1a45b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;735102f229f1a45b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SPC&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;3c2e7c6f438349e4&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;daff84b6f7fe1f97&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;3c2e7c6f438349e4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;daff84b6f7fe1f97&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094CE&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow226.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-226&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;spc-chart-rules-that-actually-matter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#spc-chart-rules-that-actually-matter&quot;&gt;SPC Chart Rules That Actually Matter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Control limits catch obvious problems. But subtle issues need pattern recognition. Here are the four rules that catch 95% of real problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rule 1: Any point outside limits&lt;/strong&gt;
This one is fairly obvious:  If a measurement point falls outside of the established upper or lower limits, something is wrong.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rule 2: Seven points on one side&lt;/strong&gt;
Seven consecutive points above or below the center line means your process has shifted. Maybe a new material lot, maybe tool wear.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rule 3: Seven points trending&lt;/strong&gt;
Seven points in a row going up or down. Classic sign of tool wear or temperature drift.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rule 4: Repeating and Cyclical Patterns&lt;/strong&gt;
This rule is for recurring behaviors that the other rules miss. Cycles that repeat over time, like a regular pattern that appears at the start of every shift change or every Monday. Speak with your operators, they will likely know what these mean.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s how to implement these rules in FlowFuse:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Function&lt;/strong&gt; node onto the workspace and add the following JavaScript code to it.&lt;/li&gt;
&lt;li&gt;Replace switch node with this &lt;strong&gt;Function&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-429&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-429&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;measurements&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; current &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Rule 1: Out-of-control point (handled by SPC node)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outOfControl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;⚠️ PROCESS OUT OF CONTROL – CHECK MACHINE!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Store the current measurement&lt;/span&gt;&lt;br /&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;avg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Keep only the last 20 measurements&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;measurements&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Initialize alert message&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; alertMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;✓ Process Stable&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Check rules if we have enough data&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; recent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Rule 2: Seven points on one side of the center line&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; allAbove &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;every&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; v &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;avg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; allBelow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;every&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; v &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;avg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allAbove &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; allBelow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        alertMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;⚠️ Process shift detected – 7 points on one side of center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Rule 3: Seven points trending up or down&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; trending &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; increasing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;increasing &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;increasing &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            trending &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trending&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        alertMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; increasing&lt;br /&gt;            &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;⚠️ Increasing trend – check for tool wear&quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;⚠️ Decreasing trend – check material quality&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; alertMessage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-429&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The following image demonstrates the advanced alerting system in action, detecting specific patterns beyond simple control limit violations:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;SPC system detecting process drift in real-time, showing chart responding to simulated measurement changes and triggering alerts&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/simulated-drift-alert.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Real-time SPC monitoring detecting process drift and triggering appropriate alerts based on trend analysis&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;connecting-to-real-equipment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#connecting-to-real-equipment&quot;&gt;Connecting to Real Equipment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Time to connect your actual machines. The approach depends on what equipment you have.&lt;/p&gt;
&lt;p&gt;For modern PLCs - anything from the last decade like Siemens S7-1200/1500, Allen-Bradley ControlLogix, or Omron NX - you&#39;ll use OPC UA. It&#39;s already built into these PLCs. Enable it in the configuration, install &lt;code&gt;node-red-contrib-opcua&lt;/code&gt; from the FlowFuse palette, and point it at your PLC. The endpoint looks like &lt;code&gt;opc.tcp://192.168.1.100:4840&lt;/code&gt;. Browse for your measurement tags and connect them to your SPC flow. &lt;a href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/&quot;&gt;Full OPC UA guide here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Older equipment speaks Modbus TCP. Check your manual&#39;s appendix for the register map. Install &lt;code&gt;node-red-contrib-modbus&lt;/code&gt;, configure it with your device&#39;s IP address and the register holding your measurement (like 40001 for holding registers). Almost every industrial device from the last 30 years supports this. &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Modbus tutorial here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For everything else, get creative. Old gauges with RS-232 ports work fine with a USB adapter and the serial node - &lt;a href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/&quot;&gt;see our serial port guide&lt;/a&gt;. Machines that dump CSV files can be monitored with the watch node. Manual measurements need just a simple dashboard form, one input field, one submit button. Don&#39;t overcomplicate it.&lt;/p&gt;
&lt;p&gt;Before connecting to SPC, always test with inject → protocol node → debug to make sure data flows. Once you see measurements in the debug panel, wire it to your SPC node and you&#39;re monitoring real processes.&lt;/p&gt;
&lt;h2 id=&quot;the-money-you&#39;re-leaving-on-the-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#the-money-you&#39;re-leaving-on-the-table&quot;&gt;The Money You&#39;re Leaving on the Table&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Remember that manufacturer from the forum processing 400,000 parts annually with a 4% scrap rate? That&#39;s 16,000 parts straight to the trash. At just $10 per part, that&#39;s $160,000 in annual waste. Cut that rate to 2% with SPC and you save $80,000 yearly.&lt;/p&gt;
&lt;p&gt;But here&#39;s what most people miss - the $10 part cost is just the beginning. Consider what every defective part also burned through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Machine time&lt;/strong&gt;: Say 3 minutes at $200/hour = another $10 gone&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Labor&lt;/strong&gt;: About 15 minutes handling the defect at $30/hour = $7.50 more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Materials&lt;/strong&gt;: The raw stock you&#39;ll never get back&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That &amp;quot;$10 part&amp;quot; actually cost you around $27.50 to scrap. Those 16,000 defects? Try $440,000 in real losses.&lt;/p&gt;
&lt;p&gt;SPC attacks all of this simultaneously. When your process stays in control, you&#39;re not just saving parts - you&#39;re saving machine capacity, labor hours, and materials. Plus stable processes need less inspection, letting you redeploy quality staff to improvement projects instead of firefighting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quick ROI calculation&lt;/strong&gt;: Take your annual defect count, multiply by your true cost per defect (part + machine + labor), then multiply by 0.5 for a conservative estimate. That&#39;s your yearly savings potential with SPC. Most manufacturers see payback in under 3 months.&lt;/p&gt;
&lt;p&gt;SPC works. It&#39;s not magic, it&#39;s not complicated, and it doesn&#39;t have to be expensive. It&#39;s just math applied to manufacturing data in real-time.&lt;/p&gt;
&lt;p&gt;The tools exist. Node-RED gets you started, but FlowFuse keeps you running in production. With built-in high availability, your SPC charts stay live even if a server fails. Multiple engineers can work on the same flows without conflicts. Deploy updates to 50 production lines with one click. When downtime costs thousands per hour, you need a platform built for manufacturing.&lt;/p&gt;
&lt;h2 id=&quot;start-preventing-defects-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#start-preventing-defects-today&quot;&gt;Start Preventing Defects Today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every day without SPC is money left on the table. Those 16,000 scrapped parts per year? The warranty claims from undetected drift? All preventable.&lt;/p&gt;
&lt;p&gt;Here&#39;s your path to production-ready SPC:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start Free with FlowFuse&lt;/a&gt;&lt;/strong&gt; - Get your instance running in minutes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow this tutorial&lt;/strong&gt; - Build your first SPC chart today&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect one machine&lt;/strong&gt; - Start with your most critical measurement&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expand gradually&lt;/strong&gt; - Add more parameters as you prove value&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Don&#39;t wait for the perfect plan. Don&#39;t form another committee. Pick one measurement that matters and start monitoring it today. Need help getting started? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a demo&lt;/a&gt; to discuss your specific requirements or &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact our team&lt;/a&gt; for enterprise deployment guidance.&lt;/p&gt;
&lt;p&gt;Because somewhere right now, one of your machines is drifting out of spec. The only question is whether you&#39;ll catch it in time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Build Your First SPC Dashboard Now →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/quality-control-automation-spc-charts/#references&quot;&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sixsigmaonline.org/six-sigma-statistical-process-control/&quot;&gt;Six Sigma Online - Statistical Process Control&lt;/a&gt; - Background on manufacturers saving thousands with quality control methods&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.practicalmachinist.com/forum/threads/scrap-rates.234251/&quot;&gt;Practical Machinist Forum - Scrap Rates Discussion&lt;/a&gt; - Real manufacturer example: 400,000 parts/year with 4% scrap rate&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://servicechannel.com/reports/scrap-rate/&quot;&gt;ServiceChannel - Industry Scrap Rate Report&lt;/a&gt; - Industry data confirming 4-5% scrap rates are standard&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.itl.nist.gov/div898/handbook/pmc/section1/pmc12.htm&quot;&gt;NIST Engineering Statistics Handbook - Statistical Process Control&lt;/a&gt; - Official definition and explanation of SPC principles&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Walter_A._Shewhart&quot;&gt;Walter Shewhart - Wikipedia&lt;/a&gt; - SPC creator at Bell Labs in the 1920s&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/</id>
        <title>OPC UA Tutorial: Connect and Exchange Data with Industrial Equipment</title>
        <summary>A practical guide to accessing industrial data through OPC UA server gateways</summary>
        <updated>2025-07-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OPC UA changes that.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;This hands-on guide walks you through building your first &lt;strong&gt;OPC UA integration&lt;/strong&gt; using &lt;strong&gt;Node-RED&lt;/strong&gt; and &lt;strong&gt;FlowFuse&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Connect&lt;/strong&gt; to any OPC UA server—Kepware, MatrikonOPC, or built-in PLC servers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browse&lt;/strong&gt; available tags and discover Node IDs from your equipment&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read&lt;/strong&gt; real-time values from PLCs, sensors, and industrial devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write&lt;/strong&gt; control signals and setpoints back to your systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-opc-ua%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#why-opc-ua%3F&quot;&gt;Why OPC UA?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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/IP. 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.&lt;/p&gt;
&lt;h3 id=&quot;breaking-the-cycle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#breaking-the-cycle&quot;&gt;Breaking the Cycle&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;h3 id=&quot;universal-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#universal-connectivity&quot;&gt;Universal Connectivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;information%2C-not-just-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#information%2C-not-just-data&quot;&gt;Information, Not Just Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reading a temperature value from OPC UA does not just give you &amp;quot;42.5&amp;quot;—it gives the full context: 42.5 °C, measured at 14:32:15.625 with &amp;quot;Good&amp;quot; quality, from &amp;quot;Tank_01/Temperature&amp;quot;, and includes alarm limits (10 °C / 80 °C). This context reduces guesswork and helps prevent costly mistakes.&lt;/p&gt;
&lt;h3 id=&quot;security-built-for-industry&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#security-built-for-industry&quot;&gt;Security Built for Industry&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;future-proof-investment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#future-proof-investment&quot;&gt;Future-Proof Investment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand why OPC UA is widely adopted, let’s explore how to implement it using FlowFuse Node-RED.&lt;/p&gt;
&lt;p&gt;This next section walks you through exactly what you need to get started with a working setup, whether for prototyping or production.&lt;/p&gt;
&lt;h3 id=&quot;what-you%E2%80%99ll-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#what-you%E2%80%99ll-need&quot;&gt;What You’ll Need&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before diving into the flow-building process, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An OPC UA server (like Kepware, MatrikonOPC, or built into your PLC)&lt;/li&gt;
&lt;li&gt;A FlowFuse Node-RED instance running on your edge device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;installing-opc-ua-support-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#installing-opc-ua-support-in-flowfuse&quot;&gt;Installing OPC UA Support in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To work with OPC UA in FlowFuse Node-RED, you will first need to install the required nodes.&lt;/p&gt;
&lt;h4 id=&quot;install-the-opc-ua-node-package&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#install-the-opc-ua-node-package&quot;&gt;Install the OPC UA Node Package&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;FlowFuse Node-RED editor&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click the menu in the top-right and choose &lt;strong&gt;Manage palette&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Install&lt;/strong&gt; tab and search for &lt;code&gt;node-red-contrib-opcua&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once installed, you will find new nodes for OPC UA communication in your palette, including &lt;strong&gt;Client&lt;/strong&gt;, &lt;strong&gt;Item&lt;/strong&gt;, and &lt;strong&gt;Browser&lt;/strong&gt; and other OPC UA nodes.&lt;/p&gt;
&lt;h3 id=&quot;connecting-to-your-opc-ua-server&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#connecting-to-your-opc-ua-server&quot;&gt;Connecting to Your OPC UA Server&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To begin accessing industrial data, create a client connection using the OPC UA Client node.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;OPC UA Client&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click to configure it.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; icon to create a new endpoint configuration.&lt;/li&gt;
&lt;li&gt;Enter your OPC UA server address, for example: &lt;code&gt;opc.tcp://192.168.0.10:4840&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set the security mode to &lt;strong&gt;None&lt;/strong&gt; (you can add security later).&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; This tutorial uses &lt;strong&gt;&amp;quot;None&amp;quot;&lt;/strong&gt; for the security setting to keep things simple.
In production environments, always use appropriate security—typically &lt;strong&gt;&amp;quot;Sign &amp;amp; Encrypt&amp;quot;&lt;/strong&gt; with certificates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt;, then &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OPC UA endpoint configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-endpoint-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OPC UA endpoint configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With the connection now defined, you’re ready to explore what tags are available.&lt;/p&gt;
&lt;h3 id=&quot;browsing-tags-(optional)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#browsing-tags-(optional)&quot;&gt;Browsing Tags (Optional)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt;, &lt;strong&gt;OPC UA Browser&lt;/strong&gt;, and &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the &lt;strong&gt;Browser&lt;/strong&gt; node, then connect the Browser&#39;s output to the Debug node.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Browser&lt;/strong&gt; node, set the topic to &lt;code&gt;ns=0;i=85&lt;/code&gt; (the root &lt;em&gt;Objects&lt;/em&gt; folder).&lt;/li&gt;
&lt;li&gt;Configure the Inject node to send a timestamp.&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the Inject node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tag information will be printed to the debug sidebar. You can now identify the exact Node IDs to use in your reads or writes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OPC UA Browser node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-browser.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OPC UA Browser node&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-227&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow227 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c3a8303048e6588f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f66e9c91c269e7fb&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;c0f8c79fc00845c8&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;ns=0;i=85&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3428199852f9fcdc&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1549f797c58ba667&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f66e9c91c269e7fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c3a8303048e6588f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3428199852f9fcdc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f66e9c91c269e7fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c0f8c79fc00845c8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow227.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-227&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;reading-tag-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#reading-tag-values&quot;&gt;Reading Tag Values&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you know the Node IDs, you can start reading data from your industrial equipment through the OPC UA server.&lt;/p&gt;
&lt;h4 id=&quot;reading-a-single-tag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#reading-a-single-tag&quot;&gt;Reading a Single Tag&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Here’s how to read a single value in real time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas (this will trigger the read operation).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;OPC UA Item&lt;/strong&gt; node and configure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node ID&lt;/strong&gt;: Enter the tag’s identifier (e.g., &lt;code&gt;ns=3;i=1003&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Type&lt;/strong&gt;: Select the appropriate type (e.g., &lt;code&gt;Boolean&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OPC UA Item node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-item-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &lt;strong&gt;Inject&lt;/strong&gt; node to the input of the &lt;strong&gt;Item&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;OPC UA Client&lt;/strong&gt; node and set its &lt;strong&gt;Action&lt;/strong&gt; to &lt;code&gt;read&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OPC UA Client node configured for reading&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-client-read-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the endpoint configuration you created earlier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &lt;strong&gt;Item&lt;/strong&gt; node to the input of the &lt;strong&gt;Client&lt;/strong&gt; node, then connect the &lt;strong&gt;Client&lt;/strong&gt; node&#39;s top output to a &lt;strong&gt;Debug&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;OPC UA Client&lt;/strong&gt; node has three outputs: the top carries the data payload, the middle indicates connection status, and the bottom provides raw responses for debugging.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Deploy the flow and click the &lt;strong&gt;Inject&lt;/strong&gt; button to trigger the read.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You should see the tag value appear in the debug panel. This confirms that communication is working correctly.&lt;/p&gt;
&lt;p&gt;You can also pass the Node ID dynamically using &lt;code&gt;msg.topic&lt;/code&gt; from the Inject node if you prefer not to use an Item node.&lt;/p&gt;
&lt;div id=&quot;nr-flow-228&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow228 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d128582dda7adbed&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a4df18253e5a79a0&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;read&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3fc16bf912f16169&#92;&quot;],[&#92;&quot;17724a6889ec7378&#92;&quot;],[&#92;&quot;c6b0f16ef7371699&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3fc16bf912f16169&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Tag Value&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2691196551812a21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=3;i=1001&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Boolean&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA Item Node&#92;&quot;,&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d128582dda7adbed&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96d17841a7f13ac4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read tag&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2691196551812a21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;17724a6889ec7378&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c6b0f16ef7371699&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Raw Respons&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a4df18253e5a79a0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.0.10:4840&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow228.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-228&#39;) })&lt;/script&gt;
&lt;h4 id=&quot;reading-multiple-tags&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#reading-multiple-tags&quot;&gt;Reading Multiple Tags&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Batch reading improves performance when you need multiple data points from your equipment&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;OPC UA Client&lt;/strong&gt; node and set its &lt;strong&gt;Action&lt;/strong&gt; to &amp;quot;READ MULTIPLE&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing OPC UA Client node with &amp;quot;READ MULTIPLE&amp;quot; action selected&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/read-multiple.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot showing OPC UA Client node with &amp;quot;READ MULTIPLE&amp;quot; action selected&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Select the endpoint configuration.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;OPC UA Item&lt;/strong&gt; node for each tag you want to read.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;Inject&lt;/strong&gt; node for each Item node to trigger it.&lt;/li&gt;
&lt;li&gt;Connect each Inject node to its corresponding Item node.&lt;/li&gt;
&lt;li&gt;Wire all Item nodes into the OPC UA Client node.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node to the top output of the &lt;strong&gt;Client&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;li&gt;Click each Inject node once, the client node will store the tag definitions.&lt;/li&gt;
&lt;li&gt;Send a message with &lt;code&gt;msg.topic = &amp;quot;readmultiple&amp;quot;&lt;/code&gt; to trigger the actual read.&lt;/li&gt;
&lt;li&gt;To clear stored items, send &lt;code&gt;msg.topic = &amp;quot;clearitems&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You now have a flexible setup for reading multiple values from your PLC on demand.&lt;/p&gt;
&lt;div id=&quot;nr-flow-229&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow229 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6f5e2b1cbce15025&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;readmultiple&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;28b575f06bbbe7a7&#92;&quot;],[&#92;&quot;139d346aab204f2f&#92;&quot;],[&#92;&quot;3497d5566fb78f5f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4daa958d34c648c5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=5;s=Counter1&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Int32&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f5e2b1cbce15025&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;baa2733ca1fcb69d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add item&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4daa958d34c648c5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dfd96a4dfe6330af&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=5;s=Random1&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Double&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f5e2b1cbce15025&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b8d5e40a98b1fb9f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add item&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dfd96a4dfe6330af&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3f63c46f499c3bca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read multiple items&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;readmultiple&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f5e2b1cbce15025&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;75c7927996cf44c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Clear nodeId array&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;clearitems&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f5e2b1cbce15025&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;28b575f06bbbe7a7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Tag Value&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;139d346aab204f2f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3497d5566fb78f5f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Raw Response&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow229.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-229&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;writing-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#writing-values&quot;&gt;Writing Values&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to reading data, OPC UA also allows you to write control signals or parameters to your equipment.&lt;/p&gt;
&lt;h4 id=&quot;writing-a-single-tag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#writing-a-single-tag&quot;&gt;Writing a Single Tag&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To write a single value:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas (used to trigger the write operation).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;OPC UA Item&lt;/strong&gt; node and configure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node ID&lt;/strong&gt;: Enter the target identifier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Type&lt;/strong&gt;: Choose the appropriate type (e.g., &lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;Double&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value&lt;/strong&gt;: Enter the value to write.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing OPC UA Item node configuration for write operation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-item-node-write.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;OPC UA Item node configured for a write operation&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;Inject&lt;/strong&gt; node to the &lt;strong&gt;Item&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;OPC UA Client&lt;/strong&gt; node and set its &lt;strong&gt;Action&lt;/strong&gt; to &lt;code&gt;WRITE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing OPC UA Client node with &amp;quot;WRITE&amp;quot; action selected&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-client-write-ops.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;OPC UA Client node with &amp;quot;WRITE&amp;quot; action selected&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the endpoint configuration you created earlier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;Item&lt;/strong&gt; node to the &lt;strong&gt;Client&lt;/strong&gt; node, then connect the &lt;strong&gt;Client&lt;/strong&gt; node&#39;s top output to a &lt;strong&gt;Debug&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and click the &lt;strong&gt;Inject&lt;/strong&gt; button to trigger the write.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The OPC UA Client node will confirm the operation with a status like &lt;strong&gt;&amp;quot;values written&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;div id=&quot;nr-flow-230&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow230 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c922a70d48ecba6f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7eb010a4671ac181&#92;&quot;],[&#92;&quot;392bb1fd60c29baf&#92;&quot;],[&#92;&quot;e9d279677dbc87e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5ff1e3c2d5977a34&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=5;s=Counter1&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Int32&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;20&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c922a70d48ecba6f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8cdd141dbdb350c7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5ff1e3c2d5977a34&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7eb010a4671ac181&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Tag Value&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:680,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;392bb1fd60c29baf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e9d279677dbc87e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Raw Response&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow230.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-230&#39;) })&lt;/script&gt;
&lt;h4 id=&quot;writing-multiple-tags&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#writing-multiple-tags&quot;&gt;Writing Multiple Tags&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To write multiple values at once, follow this pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;OPC UA Client&lt;/strong&gt; node and set its &lt;strong&gt;Action&lt;/strong&gt; to &lt;code&gt;WRITE MULTIPLE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing OPC UA Client node with &amp;quot;WRITE MULTIPLE&amp;quot; action selected&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-client-write-multiple.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;OPC UA Client node configured for writing multiple values&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the appropriate endpoint configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add multiple &lt;strong&gt;OPC UA Item&lt;/strong&gt; nodes, each configured with a &lt;strong&gt;Node ID&lt;/strong&gt;, &lt;strong&gt;Data Type&lt;/strong&gt;, and &lt;strong&gt;Value&lt;/strong&gt; to be written.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;Inject&lt;/strong&gt; node for each &lt;strong&gt;Item&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect each &lt;strong&gt;Inject&lt;/strong&gt; node to its corresponding &lt;strong&gt;Item&lt;/strong&gt; node, then connect all &lt;strong&gt;Item&lt;/strong&gt; nodes to the &lt;strong&gt;Client&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node to the top output of the &lt;strong&gt;Client&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow and trigger all &lt;strong&gt;Inject&lt;/strong&gt; nodes to load the values.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To execute the write operation, send a message with &lt;code&gt;msg.topic = &amp;quot;writemultiple&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To clear the stored items, send a message with &lt;code&gt;msg.topic = &amp;quot;clearitems&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This setup allows you to prepare multiple tag values and write them all at once, giving you precise control through a single command.&lt;/p&gt;
&lt;div id=&quot;nr-flow-231&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow231 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ed421a9.d6319e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;writemultiple&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxMessageSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;receiveBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sendBufferSize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;setstatusandtime&#92;&quot;:false,&#92;&quot;keepsessionalive&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:560,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b0788fb9285c48ea&#92;&quot;],[&#92;&quot;bde690208cbf2c4c&#92;&quot;],[&#92;&quot;0883826b4a0ca030&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96bd763.14a9308&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=3;i=1007&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Double&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;1.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ed421a9.d6319e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d8a68c7a.a73008&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add item&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;96bd763.14a9308&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8ae51c8c.20bd3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=3;i=1008&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Int32&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ed421a9.d6319e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1335adce.7f46ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add item&#92;&quot;,&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8ae51c8c.20bd3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2c050a3d.91f496&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write multiple items&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;writemultiple&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ed421a9.d6319e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;690e4f9f.faeca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Clear nodeId array&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;clearitems&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ed421a9.d6319e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b0788fb9285c48ea&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Tag Value&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bde690208cbf2c4c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Errors&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0883826b4a0ca030&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ead97ed756a13a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Raw Response&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow231.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-231&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;what%E2%80%99s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/reading-and-writing-plc-data-using-opc-ua/#what%E2%80%99s-next&quot;&gt;What’s Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;In real deployments, you will want more than Inject nodes and debug panels. With &lt;strong&gt;FlowFuse Dashboard 2.0&lt;/strong&gt;, you can build full operator interfaces—live gauges, control buttons, trend charts—fully connected to your OPC UA data.&lt;/p&gt;
&lt;p&gt;This guide covered the basics, but OPC UA offers far more. In the next article, we will explore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subscriptions for real-time monitoring without polling&lt;/li&gt;
&lt;li&gt;Events and alarms directly from equipment&lt;/li&gt;
&lt;li&gt;Historical data queries for trend analysis&lt;/li&gt;
&lt;li&gt;Method calls to execute functions on your devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When it is time to move beyond prototypes, &lt;strong&gt;FlowFuse&lt;/strong&gt; 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.&lt;/p&gt;
&lt;p&gt;If you’re ready to simplify your OPC UA integration and scale industrial workflows with Node-RED, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;start your free trial&lt;/a&gt; of FlowFuse today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/</id>
        <title>Node-RED Serial Port Tutorial: Connect RS232/RS485 Manufacturing Equipment</title>
        <summary>Learn how to bring serial-connected equipment online using Node-RED and FlowFuse</summary>
        <updated>2025-07-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Many factories rely on machines, both new and old, that communicate via traditional serial interfaces such as &lt;strong&gt;RS-232, RS-422, or RS-485&lt;/strong&gt;. These machines remain reliable but can be challenging to integrate with modern systems due to their connectivity style.&lt;/p&gt;
&lt;p&gt;This guide shows you how to use FlowFuse (Node-RED with enterprise capabilities) to connect manufacturing equipment, collect data, and enable real-time monitoring—without modifying your original hardware.&lt;/p&gt;
&lt;h2 id=&quot;making-sense-of-serial-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#making-sense-of-serial-communication&quot;&gt;Making Sense of Serial Communication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into the wiring and flow configuration, it helps to understand how serial communication works—and why it is still relevant in industrial settings.&lt;/p&gt;
&lt;p&gt;Serial ports move data one bit at a time, like passing beads on a string. This may sound old-fashioned, but it remains one of the most reliable and predictable ways to connect machines.&lt;/p&gt;
&lt;h3 id=&quot;data-direction%3A-which-way-does-it-flow%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#data-direction%3A-which-way-does-it-flow%3F&quot;&gt;Data Direction: Which Way Does It Flow?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Not all serial connections behave the same. The direction of data flow is defined by its duplex mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simplex&lt;/strong&gt;: One-way only. Like a speaker giving a lecture—the machine talks, you just listen. This is common for devices like weight scales or scanners that only output data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Half-Duplex&lt;/strong&gt;: Data can flow in both directions, but only one side can transmit at a time. This is like using a walkie-talkie. It is the most common operational mode for &lt;strong&gt;RS-485&lt;/strong&gt; (using two wires), where multiple devices share the same communication line.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full-Duplex&lt;/strong&gt;: Two-way, simultaneous communication. This is like a phone call—both sides can talk and listen at once. This is the typical mode for &lt;strong&gt;RS-232&lt;/strong&gt; (using separate transmit and receive lines) and &lt;strong&gt;RS-422&lt;/strong&gt;, which is designed for full-duplex, multi-drop scenarios (one sender, multiple listeners).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Across industrial environments, serial interfaces like &lt;strong&gt;RS-232, RS-422, and RS-485&lt;/strong&gt; remain prevalent for device communication, depending on the wiring and number of connected devices.&lt;/p&gt;
&lt;h3 id=&quot;data-format%3A-how-is-it-structured%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#data-format%3A-how-is-it-structured%3F&quot;&gt;Data Format: How Is It Structured?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Machines are picky—they expect data to arrive in a specific format. Here are the key pieces that make up a serial data &lt;strong&gt;frame&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Setting&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;What It Means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Baud Rate&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Speed of transmission (e.g., 9600 or 115200)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Data Bits&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;The actual data, usually 7 or 8 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Parity&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Optional error check—even, odd, or none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;&lt;strong&gt;Stop Bits&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Marks the end of each message&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;interface-types%3A-how-devices-physically-connect&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#interface-types%3A-how-devices-physically-connect&quot;&gt;Interface Types: How Devices Physically Connect&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Different machines use different physical standards. The most common are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RS-232&lt;/strong&gt;: Typically full-duplex and one-to-one. Good for short-distance device communication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RS-422&lt;/strong&gt;: Full-duplex, multi-drop (one sender, multiple receivers). Used for longer distances than RS-232.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RS-485&lt;/strong&gt;: Typically half-duplex and multi-device. Ideal for networks and even longer cable runs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USB (via adapter)&lt;/strong&gt;: Most modern PCs and gateways use USB-to-Serial adapters to talk to RS-232/422/485 devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setting-up-serial-communication-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#setting-up-serial-communication-with-flowfuse&quot;&gt;Setting Up Serial Communication with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand how serial communication works and what kind of interfaces your machine might use, the next step is to put that knowledge into practice.&lt;/p&gt;
&lt;p&gt;Using &lt;strong&gt;FlowFuse&lt;/strong&gt;, you can easily establish serial communication, process the data, and integrate it into dashboards or automated workflows, all without modifying the original hardware.&lt;/p&gt;
&lt;p&gt;Let&#39;s walk through how to set this up.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we start, ensure the following prerequisites are met:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hardware Connection:&lt;/strong&gt; The machine must be physically connected to your system using a serial interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Instance:&lt;/strong&gt; Make sure you have an instance of Node-RED up and running. The quickest way to do this is via FlowFuse. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serialport Node:&lt;/strong&gt; Install the &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-serialport&quot;&gt;node-red-node-serialport&lt;/a&gt; package if it is not already available in your palette.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;configuring-the-serial-port-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#configuring-the-serial-port-node&quot;&gt;Configuring the Serial Port Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After installing the &lt;code&gt;node-red-node-serialport&lt;/code&gt; package, follow these steps to configure serial communication in your Node-RED flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Serial In&lt;/strong&gt; node from the Node-RED palette onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the node to open the configuration dialog.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the pencil icon next to the &lt;strong&gt;Serial Port&lt;/strong&gt; field to add a new port configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the serial port path (e.g., &lt;code&gt;/dev/ttyUSB0&lt;/code&gt; on Linux or &lt;code&gt;COM3&lt;/code&gt; on Windows). You can also click the &lt;strong&gt;search&lt;/strong&gt; option to list available ports.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of Node-RED serial port node configuration showing available serial ports after clicking the search option.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/searching-path.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Node-RED serial port node configuration showing available serial ports after clicking the search option.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Set the &lt;strong&gt;baud rate&lt;/strong&gt;, &lt;strong&gt;data bits&lt;/strong&gt;, &lt;strong&gt;stop bits&lt;/strong&gt;, and &lt;strong&gt;parity&lt;/strong&gt; according to your machine’s specifications. These values must match the device exactly, or communication will fail or result in corrupted data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, define an &lt;strong&gt;input delimiter&lt;/strong&gt;, such as &lt;code&gt;&#92;n&lt;/code&gt; or &lt;code&gt;&#92;r&lt;/code&gt;, to segment incoming messages if your device sends data in lines or chunks.
If the output is fixed-length, you can configure it to wait for a specific number of characters. You can also set a &lt;strong&gt;timeout&lt;/strong&gt; to receive data at regular intervals.
Later in the output section, you can choose to &lt;strong&gt;add characters&lt;/strong&gt; back to the message, such as restoring the line break.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of input and output settings in the Node-RED serial port node, showing options like delimiter, character count, and timeout.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/input-output-serial-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of input and output settings in the Node-RED serial port node, showing options like delimiter, character count, and timeout.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the serial port is correctly configured and the device is connected, the &lt;strong&gt;serial in&lt;/strong&gt; node will show a &amp;quot;connected&amp;quot; status below the node with a small green square.&lt;/p&gt;
&lt;p data-zoomable=&quot;&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Serial In node in Node-RED showing a green square that indicates a successful connection to the serial port.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/serial-port-node-status.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Serial In node in Node-RED showing a green square that indicates a successful connection to the serial port.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;writing-to-serial-port&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#writing-to-serial-port&quot;&gt;Writing to Serial Port&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To send data to a machine, use the &lt;strong&gt;serial out&lt;/strong&gt; node in Node-RED. This is often necessary to trigger actions such as starting a process, requesting a reading, or changing an internal state.&lt;/p&gt;
&lt;p&gt;Follow these steps to send a command:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;payload type&lt;/strong&gt; appropriate to your machine’s requirements. This could be a string, number, raw buffer, or JSON object.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;serial out&lt;/strong&gt; node and select the configured serial port.&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;inject&lt;/strong&gt; node to the &lt;strong&gt;serial out&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, clicking the inject button will send the specified data to the machine via the serial interface.&lt;/p&gt;
&lt;p&gt;In this guide, we are using a real machine connected via a serial interface. The machine is programmed to simulate a production process when it receives the &lt;code&gt;&amp;quot;START&amp;quot;&lt;/code&gt; command (sent as a string). Once triggered, it begins incrementing the count of good and defect products and sends this data back over the same serial connection.&lt;/p&gt;
&lt;p&gt;The next section demonstrates how to read and process this simulated production data using the &lt;strong&gt;serial in&lt;/strong&gt; node.&lt;/p&gt;
&lt;h3 id=&quot;reading-and-processing-serial-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#reading-and-processing-serial-data&quot;&gt;Reading and Processing Serial Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Follow these steps to read and handle the serial data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;serial in&lt;/strong&gt; node onto the canvas and configure it to use the same serial port.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;debug&lt;/strong&gt; node and connect it to the output of the &lt;strong&gt;serial in&lt;/strong&gt; node. This helps you inspect the raw payload and confirm that data is being received correctly.&lt;/li&gt;
&lt;li&gt;Once you confirm the format of the incoming data, use any of the &lt;strong&gt;change&lt;/strong&gt;, &lt;strong&gt;JSON&lt;/strong&gt;, or &lt;strong&gt;function&lt;/strong&gt; node to parse and convert it into a structured format, here we have used function.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In our case, the machine sends production data every 2 seconds in the following format:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of Node-RED debug panel showing production data sent from the machine every 2 seconds&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/debug-panel-output.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Node-RED debug panel showing production data sent from the machine every 2 seconds.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To convert this string into a structured JSON object, you can use a &lt;strong&gt;function&lt;/strong&gt; node with the following code:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-285&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-285&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; parts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39; &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;parts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; part&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-285&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This transforms the string into a JSON object like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-289&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-289&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;GOOD&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;214&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;DEFECT&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-289&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: You do not need to know JavaScript to use the &lt;strong&gt;function&lt;/strong&gt; node.
If you are using FlowFuse, the built-in &lt;a href=&quot;https://www.google.com/search?q=/docs/user/expert/&quot;&gt;FlowFuse Assistant&lt;/a&gt; can help you write function code using natural language. Simply provide a sample of the data received from your machine and describe the output you expect — the Assistant will generate the function for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;handling-request-response-serial-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#handling-request-response-serial-communication&quot;&gt;Handling Request-Response Serial Communication&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Not all machines stream data continuously. Some expect a request command, and only then respond with data. In these cases, using a combination of &lt;strong&gt;inject&lt;/strong&gt;, &lt;strong&gt;serial out&lt;/strong&gt;, and &lt;strong&gt;serial in&lt;/strong&gt; nodes can become tricky—especially if you need to match each request with exactly one response. That’s where the &lt;strong&gt;serial request&lt;/strong&gt; node becomes useful.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;serial request&lt;/strong&gt; node handles this entire pattern for you. Internally, it combines the logic of sending a message and waiting for a single reply, working in a &lt;strong&gt;first-in, first-out&lt;/strong&gt; manner. This means it will only send the next request after receiving a response (or timeout) for the previous one, making it ideal for synchronous devices.&lt;/p&gt;
&lt;p&gt;To use it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;serial request&lt;/strong&gt; node from the palette.&lt;/li&gt;
&lt;li&gt;Double-click to configure the port—use the same path and settings as your other serial nodes.&lt;/li&gt;
&lt;li&gt;Connect it to an &lt;strong&gt;inject&lt;/strong&gt; node configured with the command your machine expects, such as &lt;code&gt;&amp;quot;READ&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;STATUS&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the output side, connect a &lt;strong&gt;debug&lt;/strong&gt; or &lt;strong&gt;function&lt;/strong&gt; node to handle the response.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each time you trigger the inject, the command will be sent over the serial port, and the response will be delivered to the output—ready to be parsed just like before. This approach is clean, predictable, and removes the guesswork from matching writes with reads.&lt;/p&gt;
&lt;p&gt;The output message includes &lt;code&gt;msg.payload&lt;/code&gt; containing the response (if any), &lt;code&gt;msg.status&lt;/code&gt; with the result status, and &lt;code&gt;msg.port&lt;/code&gt; for reference.&lt;/p&gt;
&lt;p&gt;This node is especially useful for polling machines that respond with production counts, part IDs, temperature readings, or system status—but only when asked.&lt;/p&gt;
&lt;h3 id=&quot;dynamically-managing-serial-ports&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#dynamically-managing-serial-ports&quot;&gt;Dynamically Managing Serial Ports&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a perfect setup, the serial device is connected, the port is stable, and everything just works. But in practice, hardware is not always so predictable.&lt;/p&gt;
&lt;p&gt;For example, You might disconnect and reconnect a USB-to-serial adapter—and now the device shows up as &lt;code&gt;/dev/ttyUSB1&lt;/code&gt; instead of &lt;code&gt;/dev/ttyUSB0&lt;/code&gt;. Or maybe you need to temporarily release the serial port to flash new firmware onto an Arduino. In some environments, the port assignment could change on every reboot, making it difficult to hardcode anything.&lt;/p&gt;
&lt;p&gt;Rather than redeploying or editing your flow every time, Node-RED gives you a more flexible option: the &lt;strong&gt;serial control&lt;/strong&gt; node.&lt;/p&gt;
&lt;p&gt;This node lets your flow adjust serial communication settings on the fly. You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stop the serial connection when needed.&lt;/li&gt;
&lt;li&gt;Start it again later.&lt;/li&gt;
&lt;li&gt;Even switch to a different port entirely—without touching the Node-RED editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this happens by sending a simple message to the control node.&lt;/p&gt;
&lt;p&gt;To stop communication:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-376&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-376&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-376&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;To start it again:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-380&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-380&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-380&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;And if the port changes or needs reconfiguration, you can send everything in one message:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-384&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-384&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;serialport&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/dev/ttyUSB1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;serialbaud&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;databits&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;parity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;stopbits&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-384&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This is especially useful when your flow needs to recover automatically—for example, after a USB reconnection—or if you want to let a user select the correct port from a dashboard interface.&lt;/p&gt;
&lt;p&gt;Each time a message is received, the node also outputs the current port configuration. This allows you to log or verify changes as part of your flow—making it easy to track what the system is doing behind the scenes.&lt;/p&gt;
&lt;p&gt;In short, the &lt;strong&gt;serial control&lt;/strong&gt; node adds a layer of resilience and flexibility that is often essential in real-world deployments—where devices come and go, ports are never quite consistent, and downtime is not an option.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/connect-legacy-equipment-serial-flowfuse/#key-takeaways&quot;&gt;Key Takeaways&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Manufacturing floors often bring together a mix of old and new machines. Among them, many still operate on traditional communication methods that are reliable but difficult to integrate with modern systems. These machines continue to perform their core functions well, but without connectivity, they remain isolated from digital workflows.&lt;/p&gt;
&lt;p&gt;With FlowFuse and Node-RED, you can bridge that gap—bringing equipment online without changing or replacing existing hardware. From data collection to triggering actions and monitoring performance, your machines can become part of a connected and intelligent system.&lt;/p&gt;
&lt;p&gt;Whether you’re in textiles, precision engineering, or automotive manufacturing, FlowFuse helps you unlock the full potential of your existing equipment. No rip-and-replace needed—just smarter connections. &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Get in touch with us&lt;/a&gt; and start building your serial integration flow today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/</id>
        <title>How we Built a Smart Manufacturing Order Execution Panel with FlowFuse</title>
        <summary>Control and track manufacturing orders with FlowFuse</summary>
        <updated>2025-07-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A few days ago, I had a conversation with a solution architect about how the lack of integration between the shop floor and business systems often leads to missed opportunities and financial losses. He also mentioned that while many manufacturers want to bridge this gap, they often hesitate — mostly due to concerns about complexity of integration or fear of disrupting existing operations.&lt;/p&gt;
&lt;p&gt;But there is no need to be afraid. In this blog, I will walk you through a simple demo that shows how easy it can be to connect production systems with your ERP. With just a small integration, you can improve visibility, avoid manual errors, and prevent unnecessary losses.&lt;/p&gt;
&lt;p&gt;To demonstrate this, I built a smart Manufacturing Order (MO) execution panel using FlowFuse, connected to ERP.&lt;/p&gt;
&lt;p&gt;Let’s take a closer look.&lt;/p&gt;
&lt;h2 id=&quot;demo%3A-smart-manufacturing-order-execution-panel-in-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#demo%3A-smart-manufacturing-order-execution-panel-in-action&quot;&gt;Demo: Smart Manufacturing Order Execution Panel in Action&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;M_CIoHiSW6s&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;In this demonstration, an operator starts by selecting a Manufacturing Order (MO) from a list pulled directly from Odoo ERP. The system immediately checks if enough raw materials are available for that specific order.&lt;/p&gt;
&lt;p&gt;If the materials are ready, production begins, and the MO status in Odoo is automatically updated to In Progress. The system then tracks the production count in real time. However, if materials are missing, production won’t start, and the operator is notified instantly. Once the produced quantity matches the target, the system automatically stops the line and marks the MO as Done in Odoo, completing the cycle without manual intervention.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works%3A-behind-the-scenes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#how-it-works%3A-behind-the-scenes&quot;&gt;How It Works: Behind the Scenes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To build this system, I used &lt;strong&gt;FlowFuse&lt;/strong&gt; to create a Node-RED flow that connects to &lt;strong&gt;Odoo ERP&lt;/strong&gt; and controls a simulated production line.&lt;/p&gt;
&lt;h3 id=&quot;system-components&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#system-components&quot;&gt;System Components&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Odoo ERP&lt;/strong&gt;&lt;br /&gt;
Holds Manufacturing Orders, product details, and inventory data. This integration allows for a two-way conversation between the shop floor and the business&#39;s core planning system. For a detailed guide on how to read from and write to Odoo, you can read our article, &lt;a href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/&quot;&gt;Connect Your Shop Floor to Your ERP – Odoo Edition&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse&lt;/strong&gt;&lt;br /&gt;
Executes logic such as fetching manufacturing orders, checking material availability, updating statuses, controlling production, and building the operator interface.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simulated Production Line (Factory I/O)&lt;/strong&gt;&lt;br /&gt;
Acts as the shop floor. Starts and stops production based on FlowFuse commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PLC&lt;/strong&gt;&lt;br /&gt;
Receives commands from FlowFuse and controls the actual machinery or simulated production environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;S7 Protocol (S7Comm)&lt;/strong&gt;&lt;br /&gt;
This is the protocol used to communicate with Siemens S7 series PLCs. We use Node-RED nodes within FlowFuse to send control commands (e.g., start/stop production) and read critical data (e.g., produced quantity, machine status) directly from the PLC’s memory blocks. To learn exactly how to set this up, check out our step-by-step tutorial, &lt;a href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/&quot;&gt;Getting Started: Integrating Siemens S7 PLCs with Node-RED&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is the full Node-RED flow that powers this smart manufacturing execution panel.&lt;/p&gt;
&lt;div id=&quot;nr-flow-232&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow232 = &quot;&#92;n&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Manufacturing Order Execution Panel&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;4e8b22877e33b496&#92;&quot;,&#92;&quot;a0e5e90344e88702&#92;&quot;,&#92;&quot;16744562f37152fd&#92;&quot;,&#92;&quot;f44680e87cdce3ac&#92;&quot;,&#92;&quot;b04986985da9af6d&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:99,&#92;&quot;w&#92;&quot;:1272,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;13462b8b0f1607f7&#92;&quot;,&#92;&quot;8a482fd274547e0f&#92;&quot;,&#92;&quot;3efb1c1f34d51979&#92;&quot;,&#92;&quot;41b87ca07226c044&#92;&quot;,&#92;&quot;dda4ef8740ffb258&#92;&quot;,&#92;&quot;226fe05ccb3626e4&#92;&quot;,&#92;&quot;51a994a919a9ef23&#92;&quot;,&#92;&quot;4556a1575a3c8cf0&#92;&quot;,&#92;&quot;e23884a220043451&#92;&quot;,&#92;&quot;9df108ae0c62ee39&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:1272,&#92;&quot;h&#92;&quot;:162},{&#92;&quot;id&#92;&quot;:&#92;&quot;8df3544692ccd8d8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;0ce2a3c49003ca9f&#92;&quot;,&#92;&quot;b11dfaf019777940&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:359,&#92;&quot;w&#92;&quot;:572,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e079fb2baac0a769&#92;&quot;,&#92;&quot;e8069c4a2b3f5457&#92;&quot;,&#92;&quot;1f9227a4cad571bd&#92;&quot;,&#92;&quot;c81b1fb4e1b78f64&#92;&quot;,&#92;&quot;befaaf0dd824e0e9&#92;&quot;,&#92;&quot;8f4dbf296b38a3c3&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:559,&#92;&quot;w&#92;&quot;:912,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9d1401e33f657a5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;67598322bfa17031&#92;&quot;,&#92;&quot;2c3da53c9785237d&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:459,&#92;&quot;w&#92;&quot;:352,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;c85a3940e02e9d05&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#1a1c25&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#000102&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#1a1c25&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${URL}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${EMAIL}&#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;e70720e10a4d3490&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Manufacturing Order Execution Panel&#92;&#92;t&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;127331d7913b7654&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;c85a3940e02e9d05&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;127331d7913b7654&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;9beea4acdde08f57&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;. &#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;e70720e10a4d3490&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;2aabe3e541e4ba61&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Running Order Summary&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;e70720e10a4d3490&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;9&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;9dc2b3b0074096ee&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Manufacturing Orders&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;e70720e10a4d3490&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;a75a1ee3b5119c06&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 endpoint&#92;&quot;,&#92;&quot;transport&#92;&quot;:&#92;&quot;iso-on-tcp&#92;&quot;,&#92;&quot;address&#92;&quot;:&#92;&quot;192.168.1.10&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;102&#92;&quot;,&#92;&quot;rack&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;slot&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;localtsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;localtsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;remotetsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;remotetsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;connmode&#92;&quot;:&#92;&quot;rack-slot&#92;&quot;,&#92;&quot;adapter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;busaddr&#92;&quot;:2,&#92;&quot;cycletime&#92;&quot;:1000,&#92;&quot;timeout&#92;&quot;:2000,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vartable&#92;&quot;:[{&#92;&quot;addr&#92;&quot;:&#92;&quot;QD30&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Lid Counter&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;Q1.3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;STOP&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB4,X192.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;START&#92;&quot;}]},{&#92;&quot;id&#92;&quot;:&#92;&quot;13462b8b0f1607f7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9beea4acdde08f57&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;START&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;green&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;white&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:true,&#92;&quot;enablePointerdown&#92;&quot;:false,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:false,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;51a994a919a9ef23&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4e8b22877e33b496&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a0e5e90344e88702&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a0e5e90344e88702&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-search-read&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;mrp.production&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;16744562f37152fd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;16744562f37152fd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;getActiveOrdersSummary&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const simplifiedOrders = msg.payload&#92;&#92;n    .filter(order =&amp;gt; order.state === &#92;&#92;&#92;&quot;confirmed&#92;&#92;&#92;&quot; || order.state === &#92;&#92;&#92;&quot;progress&#92;&#92;&#92;&quot;)&#92;&#92;n    .map(order =&amp;gt; {&#92;&#92;n        return {&#92;&#92;n            id: order.id,&#92;&#92;n            name: order.name,&#92;&#92;n            product: order.product_id?.[1] || &#92;&#92;&#92;&quot;Unknown&#92;&#92;&#92;&quot;,&#92;&#92;n            quantity: order.product_qty,&#92;&#92;n            state: order.state,&#92;&#92;n            availability: order.components_availability || &#92;&#92;&#92;&quot;Unknown&#92;&#92;&#92;&quot;&#92;&#92;n        };&#92;&#92;n    });&#92;&#92;n&#92;&#92;nmsg.payload = simplifiedOrders;&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f44680e87cdce3ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f44680e87cdce3ac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-table&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9dc2b3b0074096ee&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;maxrows&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;autocols&#92;&quot;:false,&#92;&quot;showSearch&#92;&quot;:false,&#92;&quot;deselect&#92;&quot;:true,&#92;&quot;selectionType&#92;&quot;:&#92;&quot;click&#92;&quot;,&#92;&quot;columns&#92;&quot;:[{&#92;&quot;title&#92;&quot;:&#92;&quot;ID&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;id&#92;&quot;,&#92;&quot;keyType&#92;&quot;:&#92;&quot;key&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;align&#92;&quot;:&#92;&quot;start&#92;&quot;},{&#92;&quot;title&#92;&quot;:&#92;&quot;Ref No &#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;name&#92;&quot;,&#92;&quot;keyType&#92;&quot;:&#92;&quot;key&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;align&#92;&quot;:&#92;&quot;start&#92;&quot;},{&#92;&quot;title&#92;&quot;:&#92;&quot;Production Item&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;product&#92;&quot;,&#92;&quot;keyType&#92;&quot;:&#92;&quot;key&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;align&#92;&quot;:&#92;&quot;start&#92;&quot;},{&#92;&quot;title&#92;&quot;:&#92;&quot;Target Quantity&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;quantity&#92;&quot;,&#92;&quot;keyType&#92;&quot;:&#92;&quot;key&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;align&#92;&quot;:&#92;&quot;start&#92;&quot;},{&#92;&quot;title&#92;&quot;:&#92;&quot;Order Status&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;state&#92;&quot;,&#92;&quot;keyType&#92;&quot;:&#92;&quot;key&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;align&#92;&quot;:&#92;&quot;start&#92;&quot;}],&#92;&quot;mobileBreakpoint&#92;&quot;:&#92;&quot;sm&#92;&quot;,&#92;&quot;mobileBreakpointType&#92;&quot;:&#92;&quot;defaults&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;replace&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b04986985da9af6d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8a482fd274547e0f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-update&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;mrp.production&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:1160,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3efb1c1f34d51979&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[     [payload.id],     {&#92;&#92;&#92;&quot;state&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;progress&#92;&#92;&#92;&quot;} ]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8a482fd274547e0f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;41b87ca07226c044&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Does the MO have a material shortage?&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload.availability&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Not Available&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:640,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;226fe05ccb3626e4&#92;&quot;],[&#92;&quot;3efb1c1f34d51979&#92;&quot;,&#92;&quot;9df108ae0c62ee39&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dda4ef8740ffb258&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;127331d7913b7654&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;allowConfirm&#92;&quot;:false,&#92;&quot;confirmText&#92;&quot;:&#92;&quot;Confirm&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1150,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;226fe05ccb3626e4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Production cannot begin for this order— required materials are not available.&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;orderSelected&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dda4ef8740ffb258&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b04986985da9af6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;9aad63553d0d5812&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;orderSelected&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1160,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;51a994a919a9ef23&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;orderSelected&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;41b87ca07226c044&#92;&quot;,&#92;&quot;4556a1575a3c8cf0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4556a1575a3c8cf0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;2aabe3e541e4ba61&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Running Order Summary&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n  &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-row&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-box&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-title&#92;&#92;&#92;&quot;&amp;gt;Reference&amp;lt;/div&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-value&#92;&#92;&#92;&quot;&amp;gt;{{ data?.name || &#39;--&#39; }}&amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-box&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-title&#92;&#92;&#92;&quot;&amp;gt;Product&amp;lt;/div&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-value&#92;&#92;&#92;&quot;&amp;gt;{{ data?.product || &#39;--&#39; }}&amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-box&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-title&#92;&#92;&#92;&quot;&amp;gt;Target&amp;lt;/div&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-value&#92;&#92;&#92;&quot;&amp;gt;{{ data?.quantity ?? &#39;--&#39; }}&amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-box&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-title&#92;&#92;&#92;&quot;&amp;gt;Produced&amp;lt;/div&amp;gt;&#92;&#92;n      &amp;lt;div class=&#92;&#92;&#92;&quot;kpi-value&#92;&#92;&#92;&quot;&amp;gt;{{ data?.producedQuantity ?? &#39;--&#39; }}&amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n  &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;script&amp;gt;&#92;&#92;n  export default {&#92;&#92;n  name: &#39;KpiDisplay&#39;,&#92;&#92;n&#92;&#92;n  props: {&#92;&#92;n    id: {&#92;&#92;n      type: String,&#92;&#92;n      required: true&#92;&#92;n    }&#92;&#92;n  },&#92;&#92;n&#92;&#92;n  data() {&#92;&#92;n    return {&#92;&#92;n      data: {&#92;&#92;n        name: &#39;&#39;,&#92;&#92;n        product: &#39;&#39;,&#92;&#92;n        quantity: null,&#92;&#92;n        producedQuantity: null&#92;&#92;n      }&#92;&#92;n    };&#92;&#92;n  },&#92;&#92;n&#92;&#92;n  mounted() {&#92;&#92;n    const eventName = &#39;msg-input:&#39; + this.id;&#92;&#92;n    console.log(&#39;Listening to socket:&#39;, eventName);&#92;&#92;n&#92;&#92;n    this.$socket.on(eventName, (msg) =&amp;gt; {&#92;&#92;n      console.log(&#39;Message received:&#39;, msg);&#92;&#92;n&#92;&#92;n      // Merge payload with defaults to avoid missing fields&#92;&#92;n      this.data = Object.assign({&#92;&#92;n        name: &#39;&#39;,&#92;&#92;n        product: &#39;&#39;,&#92;&#92;n        quantity: null,&#92;&#92;n        producedQuantity: null&#92;&#92;n      }, msg.payload);&#92;&#92;n    });&#92;&#92;n  }&#92;&#92;n};&#92;&#92;n&amp;lt;/script&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;style scoped&amp;gt;&#92;&#92;n  .kpi-row {&#92;&#92;n    display: flex;&#92;&#92;n    justify-content: space-between;&#92;&#92;n    gap: 2rem;&#92;&#92;n    margin: 1rem 0;&#92;&#92;n  }&#92;&#92;n&#92;&#92;n  .kpi-box {&#92;&#92;n    text-align: center;&#92;&#92;n    flex: 1;&#92;&#92;n  }&#92;&#92;n&#92;&#92;n  .kpi-title {&#92;&#92;n    font-size: 1.3rem;&#92;&#92;n    color: white;&#92;&#92;n    margin-bottom: 0.5rem;&#92;&#92;n  }&#92;&#92;n&#92;&#92;n  .kpi-value {&#92;&#92;n    font-size: 1.3rem;&#92;&#92;n    color: white;&#92;&#92;n  }&#92;&#92;n&amp;lt;/style&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e23884a220043451&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a75a1ee3b5119c06&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Start&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9df108ae0c62ee39&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;283e4560434b3d9d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;bool&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e23884a220043451&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0ce2a3c49003ca9f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8df3544692ccd8d8&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a75a1ee3b5119c06&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Lid Counter&#92;&quot;,&#92;&quot;diff&#92;&quot;:true,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b11dfaf019777940&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b11dfaf019777940&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8df3544692ccd8d8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;orderSelected.producedQuantity&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e079fb2baac0a769&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;orderSelected&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;befaaf0dd824e0e9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;91158f2206527fc0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;e70720e10a4d3490&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CSS&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;.v-card-title{&#92;&#92;n    text-align:center;&#92;&#92;n}&#92;&#92;nth,td{&#92;&#92;n    border: 1px solid white;&#92;&#92;n}&#92;&#92;n.nrdb-ui-led-bulb{&#92;&#92;n    height:85px !important;&#92;&#92;n    margin-left:auto;&#92;&#92;n    margin-right:auto;&#92;&#92;n}&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;page:style&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e8069c4a2b3f5457&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-update&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;mrp.production&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1f9227a4cad571bd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[     [data.id],     {&#92;&#92;&#92;&quot;state&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;done&#92;&#92;&#92;&quot;} ]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e8069c4a2b3f5457&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;67598322bfa17031&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9d1401e33f657a5&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;9beea4acdde08f57&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;STOP&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;red&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;white&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:true,&#92;&quot;enablePointerdown&#92;&quot;:false,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:false,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2c3da53c9785237d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2c3da53c9785237d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9d1401e33f657a5&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a75a1ee3b5119c06&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;STOP&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c81b1fb4e1b78f64&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;bool&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8f4dbf296b38a3c3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;befaaf0dd824e0e9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;checkIfOrderIsComplete&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;let data = msg.payload;&#92;&#92;nif (Number(data.quantity) === Number(data.producedQuantity)) {&#92;&#92;n    msg.payload = true;&#92;&#92;n    msg.data = data&#92;&#92;n    return msg;&#92;&#92;n}&#92;&#92;nreturn null;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1f9227a4cad571bd&#92;&quot;,&#92;&quot;c81b1fb4e1b78f64&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8f4dbf296b38a3c3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0a5f467b0d3f15a9&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a75a1ee3b5119c06&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;STOP&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow232.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-232&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;workflow-breakdown&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#workflow-breakdown&quot;&gt;Workflow Breakdown&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;mermaid&quot;&gt;sequenceDiagram&amp;#10;    participant Operator&amp;#10;    participant FlowFuse&amp;#10;    participant Odoo&amp;#10;    participant PLC&amp;#10;    Operator-&amp;gt;&amp;gt;FlowFuse: Select MO&amp;#10;    FlowFuse-&amp;gt;&amp;gt;Odoo: Fetch MO details&amp;#10;    Odoo--&amp;gt;&amp;gt;FlowFuse: Return MO + Material info&amp;#10;    alt Materials Available&amp;#10;        FlowFuse-&amp;gt;&amp;gt;Odoo: Update MO to &amp;quot;In Progress&amp;quot;&amp;#10;        FlowFuse-&amp;gt;&amp;gt;PLC: Start production&amp;#10;        loop While producing&amp;#10;            PLC--&amp;gt;&amp;gt;FlowFuse: Report produced quantity&amp;#10;        end&amp;#10;        FlowFuse-&amp;gt;&amp;gt;PLC: Stop production&amp;#10;        FlowFuse-&amp;gt;&amp;gt;Odoo: Update MO to &amp;quot;Done&amp;quot;&amp;#10;    else Materials Not Available&amp;#10;        FlowFuse--&amp;gt;&amp;gt;Operator: Notify: Cannot start&amp;#10;    end&amp;#10;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fetch Manufacturing Orders&lt;/strong&gt;&lt;br /&gt;
The system pulls a list of &lt;em&gt;confirmed&lt;/em&gt; or &lt;em&gt;in progress&lt;/em&gt; MOs from Odoo using HTTP requests with help of Odoo node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Raw Material Availability&lt;/strong&gt;&lt;br /&gt;
When an operator selects an MO, FlowFuse checks if enough raw materials are available in Odoo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start Production&lt;/strong&gt;&lt;br /&gt;
If materials are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The MO status is updated to &lt;em&gt;In Progress&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The simulated line starts producing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Track Quantity in Real Time&lt;/strong&gt;&lt;br /&gt;
As the line runs, FlowFuse keeps track of the produced quantity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop and Complete the MO&lt;/strong&gt;&lt;br /&gt;
When the produced quantity matches the MO target:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FlowFuse sends a stop command to the PLC&lt;/li&gt;
&lt;li&gt;The MO status in Odoo is updated to &lt;em&gt;Done&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;why-this-matters-for-business&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#why-this-matters-for-business&quot;&gt;Why This Matters for Business&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This demo might seem simple, but it solves some of the most common and expensive problems on the shop floor. Think about the daily headaches: an operator starts a big job, only to find out halfway through that a key material is missing, forcing the entire line to stop. Or, they produce 10% more than the order required, creating waste that just sits in inventory.&lt;/p&gt;
&lt;p&gt;This smart panel is designed to prevent those exact scenarios. By connecting your production line directly to your business systems, it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents material shortages&lt;/strong&gt; by automatically checking for raw materials before a job can even start.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eliminates overproduction&lt;/strong&gt; by stopping the line the moment the target quantity is hit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gets rid of manual data entry&lt;/strong&gt; by instantly updating the order status in the ERP.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means managers get a live, accurate view of what’s happening on the floor, not data from hours ago. The best part is that you don&#39;t need to overhaul your entire operation or buy a huge, complex system to get these benefits. A smart, focused integration like this can deliver real results, quickly.&lt;/p&gt;
&lt;h2 id=&quot;ready-to-connect-your-shop-floor%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/smart-manufacturing-order-panel-flowfuse/#ready-to-connect-your-shop-floor%3F&quot;&gt;Ready to Connect Your Shop Floor?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This demo shows how even a small, targeted integration between your production line and ERP can eliminate manual errors, reduce waste, and improve visibility — without overhauling your entire system.&lt;/p&gt;
&lt;p&gt;If you are exploring how to bring these kinds of improvements to your manufacturing operations, let’s talk.&lt;/p&gt;
&lt;p&gt;We’d be happy to discuss how FlowFuse can help you build custom, scalable solutions tailored to your factory’s needs.&lt;/p&gt;
&lt;p&gt;👉 &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Get in touch with us&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/</id>
        <title>FlowFuse 2.19: More Powerful AI in Node-RED, Drop-In Blueprints, Memory Monitoring, and Faster Onboarding</title>
        <summary>AI enhancements to Node-RED, streamlined onboarding with social authentication and device flow selection, improved Blueprint experience, more comprehensive performance monitoring, and a refreshed user interface.</summary>
        <updated>2025-07-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release focuses on speeding time to value with more powerful AI functionality within Node-RED, along with reducing friction for new users while enhancing the experience for existing users through improved Blueprint functionality, comprehensive performance monitoring, and a modernized interface that reflects FlowFuse&#39;s evolution.&lt;/p&gt;
&lt;h2 id=&quot;ai-enhancements-to-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#ai-enhancements-to-node-red&quot;&gt;AI Enhancements to Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;GIF of AI Flow Explainer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/assistant-0-3-0-flow-explainer-3tbNoRlb4T-1089.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;GIF of AI Flow Explainer&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The FlowFuse Expert can now do more than create a Function node based on your text instructions. With this release, you can highlight a flow in the Node-RED editor and ask the FlowFuse Expert to explain the purpose of the flow. This new functionality is perfect for learning and collaboration.&lt;/p&gt;
&lt;p&gt;You can also use the FlowFuse Expert to create Dashboard templates with HTML, VUE, Vuetify, and CSS, allowing you to build even faster.&lt;/p&gt;
&lt;p&gt;Stay tuned for more developments as we continue to add enhancements to the Node-RED editor in FlowFuse to enable even faster development.&lt;/p&gt;
&lt;h2 id=&quot;comprehensive-performance-monitoring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#comprehensive-performance-monitoring&quot;&gt;Comprehensive Performance Monitoring&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Memory in Performance Feature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Memory.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Memory Monitoring&lt;/em&gt;
Building on our existing CPU monitoring capabilities, we&#39;ve added memory usage tracking to the Performance feature. This enhancement provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete visibility into both CPU and memory utilization&lt;/li&gt;
&lt;li&gt;Better understanding of instance resource consumption&lt;/li&gt;
&lt;li&gt;More informed decision-making for scaling and optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these features, you can now get a holistic view of your instance performance and make informed decisions about resource allocation.&lt;/p&gt;
&lt;h2 id=&quot;add-blueprints-to-existing-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#add-blueprints-to-existing-instances&quot;&gt;Add Blueprints to Existing Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Blueprint Import&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/blueprint-import.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Blueprint Import&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Previously, Blueprints could only be used when creating new instances. Now you can import Blueprints into existing instances, making them much more versatile. Blueprints now appear as an option in the Import menu.&lt;/p&gt;
&lt;p&gt;And if you&#39;re running Node-RED version 4.1, when you select a Blueprint to import that uses nodes not in your current palette, it will offer to install them automatically.&lt;/p&gt;
&lt;p&gt;This change transforms Blueprints from a one-time instance creation tool into a constantly useful resource to speed your development with Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;social-sign-in-for-easy-onboarding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#social-sign-in-for-easy-onboarding&quot;&gt;Social Sign-in for Easy Onboarding&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Google Signin&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/social-sign-on.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Google Signin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To make it easier than ever to create a FlowFuse account, we&#39;ve introduced social sign-in options that allow users to create FlowFuse Cloud accounts using their Google credentials.&lt;/p&gt;
&lt;p&gt;This enhancement removes multiple steps from the onboarding process, making it significantly easier for new users to get started with FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;enhanced-device-agent-flow-selection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#enhanced-device-agent-flow-selection&quot;&gt;Enhanced Device Agent Flow Selection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Connecting your existing Node-RED instances running on remote devices is now even easier with the new Device Agent terminal file browser. When installing the Device Agent, you can now easily navigate your file system and select existing Node-RED instances through an interactive interface directly in the terminal.&lt;/p&gt;
&lt;p&gt;This improvement replaces the previous manual file path entry process with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An intuitive file browser that works directly in your terminal&lt;/li&gt;
&lt;li&gt;Easy navigation through your file system to locate flows&lt;/li&gt;
&lt;li&gt;Contextual information about flows including file size and modification dates&lt;/li&gt;
&lt;li&gt;A streamlined selection process that reduces setup friction&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;modernized-user-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#modernized-user-interface&quot;&gt;Modernized User Interface&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of New Homepage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/homepage.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Homepage&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The FlowFuse user interface was due for a restructuring in light of what users are looking for, along with a visual touchup. This release introduces a dedicated landing page that focuses on what we&#39;ve learned users want to do when they first access FlowFuse. The new homepage provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct access to relevant hosted and remote instances&lt;/li&gt;
&lt;li&gt;Smart prioritization based on recent activity and deployments&lt;/li&gt;
&lt;li&gt;Prominent display of issues requiring attention (performance alerts, errors)&lt;/li&gt;
&lt;li&gt;Recent team activity overview through audit log integration&lt;/li&gt;
&lt;li&gt;Improved layout and visual hierarchy&lt;/li&gt;
&lt;li&gt;Updated color scheme and styling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These changes make it easier to find what you are looking for within FlowFuse, address issues that may arise, and creates a more pleasant workspace.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our development team continues to focus on AI integration and workflow optimization. The upcoming releases will build on these foundational improvements while introducing more intelligent automation and development assistance features.&lt;/p&gt;
&lt;p&gt;We&#39;re also working on expanding our Blueprint library and improving the overall development experience within the Node-RED editor, with several exciting features planned for the coming months.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a complete list of everything included in our 2.19 release, check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your feedback continues to be invaluable in shaping FlowFuse&#39;s development. We&#39;d love to hear your thoughts on these new features and any suggestions for future improvements. Please share your experiences or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which of these new features are you most excited to try? Email me directly at greg@flowfuse.com - I&#39;d love to hear from you!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest way to get started is with FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; and have your Node-RED instances running in the cloud within minutes.&lt;/p&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/flowfuse-release-2-19/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get FlowFuse running locally in under 30 minutes using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/07/certified-nodes-v2/</id>
        <title>Curated Node-RED Integrations: FlowFuse Certified Nodes 2.0</title>
        <summary>FlowFuse Unveils Certified Nodes Program to Reward Quality and Ensure Long-Term Support</summary>
        <updated>2025-07-01T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/07/certified-nodes-v2/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;At FlowFuse, we believe that enterprises deserve access to the best of Node-REDs
custom nodes and solutions crafted by recognized experts who bring deep domain
knowledge and professional standards to their work. That&#39;s why we are thrilled
to announce a significant evolution of our ecosystem: &lt;strong&gt;FlowFuse Certified Nodes
v2.0&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;from-community-contribution-to-professional-partnership&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/certified-nodes-v2/#from-community-contribution-to-professional-partnership&quot;&gt;From Community Contribution to Professional Partnership&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Node-RED community has always had a pasionate and thrived on the
domain-expertise of its developers. The community has created an environment of
innovation, and now we&#39;re taking the next step to support enterprise-grade
solutions that companies are building on Node-RED today.&lt;/p&gt;
&lt;p&gt;Our new &lt;strong&gt;Certified Nodes&lt;/strong&gt; program we hope to elevate the community. We are
establishing a professional partnership with the most skilled node developers
and domain experts in the community.&lt;/p&gt;
&lt;p&gt;Here’s how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Expertise Recognition:&lt;/strong&gt; FlowFuse partners with developers who have
demonstrated deep expertise in their domains, and may have already published
nodes in their area of expertise. Ensuring our enterprise customers access the
most knowledgeable contributors in each field.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality-Driven Selection:&lt;/strong&gt; Our certification process identifies nodes that
excel in real-world environments, focusing on reliability, security,
up-to-date documentation and professional implementation standards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive Solutions:&lt;/strong&gt; We welcome both open-source innovations and
proprietary solutions. This approach allows experts to share their knowledge
broadly while also providing targeted solutions for specific industry needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-does-it-take-to-become-a-certified-publisher%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/certified-nodes-v2/#what-does-it-take-to-become-a-certified-publisher%3F&quot;&gt;What Does It Take to Become a Certified Publisher?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are seeking partners who represent the pinnacle of expertise in their
respective domains. To join our certified ecosystem, we look for developers who
demonstrate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain Expertise:&lt;/strong&gt; Deep knowledge and proven experience in the specific
technology or industry vertical their nodes address&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Professional Standards:&lt;/strong&gt; Commitment to enterprise-grade code quality,
comprehensive testing, and security best practices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Innovation:&lt;/strong&gt; Ongoing development and enhancement of features
that solve real-world enterprise challenges&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expert Support:&lt;/strong&gt; Ability to provide advanced technical support and guidance
that goes beyond basic troubleshooting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our certification process ensures that every node in the certified nodes
ecosystem meets these exacting standards. When enterprises choose certified
nodes, they gain access not just to code, but to the expertise and ongoing
support of recognized industry professionals. This creates a sustainable model
where expert knowledge is properly valued and enterprises receive the
reliability they require.&lt;/p&gt;
&lt;h2 id=&quot;why-partner-with-flowfuse%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/certified-nodes-v2/#why-partner-with-flowfuse%3F&quot;&gt;Why Partner with FlowFuse?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Joining the FlowFuse Certified Nodes v2.0 program means becoming part of an
elite community of experts. Moreover, there&#39;s now a financial reward for doing
so. FlowFuse commits a fixed percentage of our FlowFuse Enterprise Platform Fee
to be distributed quarterly to the node authors.&lt;/p&gt;
&lt;p&gt;If you are an expert developer or organization that has built exceptional
Node-RED nodes and are committed to maintaining the highest professional
standards, we want to collaborate with you. Let&#39;s work together to create a more
sustainable, professional ecosystem that connects enterprise users with the
industry&#39;s leading experts.&lt;/p&gt;
&lt;h3 id=&quot;contact-us-to-discuss-your-node-certification&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/07/certified-nodes-v2/#contact-us-to-discuss-your-node-certification&quot;&gt;Contact us to discuss your node certification&lt;/a&gt;&lt;/h3&gt;
&lt;div id=&quot;hs-form-certified-nodes-contact&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;hs-form-certified-nodes-contact-fallback&quot; class=&quot;ff-hubspot-consent-fallback text-center border bg-red-50/25 border-red-300 rounded-lg px-4 py-6&quot;&gt;
    &lt;p class=&quot;text-red-400&quot;&gt;&lt;strong&gt;Hmm… there was supposed to be a form here&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p class=&quot;text-gray-600&quot;&gt;
If this form does not load, try adjusting your privacy settings or switching browsers.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;script&gt;
    window.ffCreateHubSpotForm({
        target: &#39;#hs-form-certified-nodes-contact&#39;,
        fallbackSelector: &#39;#hs-form-certified-nodes-contact-fallback&#39;,
        region: &quot;eu1&quot;,
        portalId: &quot;26586079&quot;,
        formId: &quot;6e02fe34-13c3-442b-8c27-9a12e72bba37&quot;,
        
        onFormSubmit: function () {
            capture(&#39;cta-certified-nodes-contact&#39;, {
                &#39;page&#39;: &#39;article&#39;
            });
        },
        
    });
&lt;/script&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/</id>
        <title>Part 2: Building an Andon Task Manager with FlowFuse</title>
        <summary>Step-by-step guide to building a real-time issue reporting and task tracking system using FlowFuse.</summary>
        <updated>2025-06-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/&quot;&gt;Part 1&lt;/a&gt;, we introduced the concept of an Andon Task Manager—designed to streamline issue reporting and resolution on the factory floor—and outlined the system’s key features, user roles, and dashboard layout.&lt;/p&gt;
&lt;p&gt;In this part 2, we move from planning to implementation. The focus now shifts to building the actual system using &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (Node-RED Dashboard 2.0), hosted on the FlowFuse platform. We will begin by developing the &lt;strong&gt;Lines view&lt;/strong&gt; for regular users, along with a line selection menu. The Department View and Admin interface will follow in a later part of the series.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To simplify the development process, the implementation is divided into the following key sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialize SQLite Database&lt;/li&gt;
&lt;li&gt;Seed Demo Data: Departments &amp;amp; Lines&lt;/li&gt;
&lt;li&gt;Build Line Selection Menu&lt;/li&gt;
&lt;li&gt;Enable URL-Based Dashboard Access&lt;/li&gt;
&lt;li&gt;Create Live Request Fetch Flow (Per Line)&lt;/li&gt;
&lt;li&gt;Render Request Data in a Table&lt;/li&gt;
&lt;li&gt;Setting Up Visual Alerts and Timestamp Formatting&lt;/li&gt;
&lt;li&gt;Highlight Requests with CSS &amp;amp; Add Buttons to Update Request Status&lt;/li&gt;
&lt;li&gt;Create New Request Submission Flow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before proceeding, a basic understanding of Node-RED is recommended. If you are new to Node-RED, consider going through this &lt;a href=&quot;https://node-red-academy.learnworlds.com/course/node-red-getting-started&quot;&gt;free Node-RED Fundamentals Course&lt;/a&gt; to get started.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Organize your flows into clearly defined groups. For reference, images of each flow are provided. Please use the exact names given to each flow—this will help ensure consistency and make it easier to navigate back to specific flows when referenced later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin building the Andon Task Manager with FlowFuse, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running FlowFuse Instance:&lt;/strong&gt; Make sure you have a FlowFuse instance set up and running. If you don&#39;t have an account, check out the &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/docs/user/introduction/#creating-a-node-red-instance&quot;&gt;learn&lt;/a&gt; how to create an instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@flowfuse/node-red-dashboard:&lt;/strong&gt; Ensure you have FlowFuse Dashboard (also known as Node-RED Dashboard 2.0 in the community) installed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite Contrib Node:&lt;/strong&gt; Install &lt;code&gt;node-red-contrib-sqlite&lt;/code&gt; to handle local data storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Multi-user Andon:&lt;/strong&gt; Install &lt;code&gt;@flowfuse/node-red-dashboard-2-user-addon&lt;/code&gt; to enable multi-user support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable FlowFuse User Authentication:&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#enabling-flowfuse-user-authentication&quot;&gt;Enable FlowFuse User Authentication&lt;/a&gt; on your FlowFuse instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Moment Contrib Node:&lt;/strong&gt; Install &lt;code&gt;node-red-contrib-moment&lt;/code&gt; for date and time formatting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;initialize-sqlite-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#initialize-sqlite-database&quot;&gt;Initialize SQLite Database&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step is to set up a database to store requests and their updates.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and configure it to trigger on Deploy, after a delay of 0.1 seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;SQLite&lt;/strong&gt; node onto the canvas. Double-click and click the &lt;strong&gt;+&lt;/strong&gt; icon to add a new database configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Give the database a name and set the mode to &lt;strong&gt;Read-Write-Create&lt;/strong&gt;. Click &lt;strong&gt;Add&lt;/strong&gt; to save.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;strong&gt;SQL Query&lt;/strong&gt; to &lt;strong&gt;Fixed statement&lt;/strong&gt; and enter:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-131&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-131&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; requests &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  rowid &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  line &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  support &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  requested &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  acknowledged &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  resolved &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  notes &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-131&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;Inject&lt;/strong&gt; node to the SQLite node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED flow showing an Inject node connected to an SQLite node to create a requests table in the database.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sqlite-create-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow to initialize the SQLite database and create the requests table.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once deployed, this will create the SQLite database and &lt;code&gt;requests&lt;/code&gt; table if it does not already exist.&lt;/p&gt;
&lt;h3 id=&quot;seed-demo-data%3A-departments-%26-lines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#seed-demo-data%3A-departments-%26-lines&quot;&gt;Seed Demo Data: Departments &amp;amp; Lines&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As discussed in the planning section, only the admin role will have the ability to add new departments and lines. Since the admin feature is not yet available, we will populate demo data using a predefined flow to allow ourself to test the application while the standard user interface is being developed.&lt;/p&gt;
&lt;div id=&quot;nr-flow-216&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow216 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Populate with demo support areas and lines&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add demo production line and department&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;34c733b480e41a13&#92;&quot;,&#92;&quot;4e46ae25d198fd1b&#92;&quot;,&#92;&quot;882e29d2dcc9326c&#92;&quot;,&#92;&quot;399bd159f46c7427&#92;&quot;,&#92;&quot;5001c1cdf6661f88&#92;&quot;],&#92;&quot;x&#92;&quot;:34,&#92;&quot;y&#92;&quot;:39,&#92;&quot;w&#92;&quot;:1302,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;34c733b480e41a13&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add production lines and department for testing&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4e46ae25d198fd1b&#92;&quot;,&#92;&quot;399bd159f46c7427&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4e46ae25d198fd1b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Is lines undefined?&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;#:(persistent)::lines&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;istype&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;undefined&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;undefined&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;882e29d2dcc9326c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;882e29d2dcc9326c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store lines to context store&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;#:(persistent)::lines&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[{&#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;T1&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;T1&#92;&#92;&#92;&quot;},{&#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;T2&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;T2&#92;&#92;&#92;&quot;}]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;399bd159f46c7427&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Is departments undefined?&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;#:(persistent)::departments&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;istype&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;undefined&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;undefined&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5001c1cdf6661f88&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5001c1cdf6661f88&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d5dd9bfc599374d4&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6471824e24f18939&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store departments to context store&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;#:(persistent)::departments&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[{&#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Maintenance&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Maintenance&#92;&#92;&#92;&quot;},{&#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Stores&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Stores&#92;&#92;&#92;&quot;},{&#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Quality&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;Quality&#92;&#92;&#92;&quot;}]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1170,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow216.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-216&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;Import the provided demo flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy&lt;/strong&gt; the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will store demo lines and departments in the global context as &lt;code&gt;global.lines&lt;/code&gt; if not already present.&lt;/p&gt;
&lt;h3 id=&quot;build-line-selection-menu&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#build-line-selection-menu&quot;&gt;Build Line Selection Menu&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let us create a new page and menu item for Production Lines. This page will list all currently available production lines, making it easier to navigate through them.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-event&lt;/strong&gt; node onto the canvas to detect page navigation.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;change&lt;/strong&gt; node and configure it to:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.lines&lt;/code&gt; to &lt;code&gt;global.get(&amp;quot;lines&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-template&lt;/strong&gt; node onto the canvas. Create a new page with name “Line Menu” and a group.&lt;/li&gt;
&lt;li&gt;Paste the following into the template:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-207&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-207&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-row&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-col&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Production Lines&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-col&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-row&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-row&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;scrollable-row&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;no-gutters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-col&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(btn, index) in lines&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:key&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;auto&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-btn&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;`/dashboard/lines?line=${btn.value}`&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;custom-btn&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rounded&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-col&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-row&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-alert&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;selectedLine&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mt-3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      Selected Line: &lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;selectedLine&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;updateButtonContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localeCompare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;msg-input:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;updateButtonContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.scrollable-row&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wrap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.scrollable-row .v-col&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;flex-shrink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.scrollable-row&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 60px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.custom-btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 44&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 52&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;margin-right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 12px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px 16px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.custom-btn:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;54&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 70&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 86&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-207&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, the dashboard will show buttons for each production line. Clicking a line redirects the user to a page with following url:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;/dashboard/lines?line=T1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED editor showing the flow setup for generating a menu of production lines using ui-event, change, and ui-template nodes.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/menu-for-lines-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED flow to create a dynamic menu for production lines on the dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Dashboard displaying styled buttons for each production line, enabling quick navigation to specific line pages.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/menu-for-lines.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard view showing production line buttons generated from the flow.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &amp;quot;line&amp;quot; URL parameter will be used in the next section to store the user&#39;s selected production line.&lt;/p&gt;
&lt;h3 id=&quot;enable-url-based-dashboard-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#enable-url-based-dashboard-access&quot;&gt;Enable URL-Based Dashboard Access&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this section, we’ll build a flow that allows users to directly access the dashboard using a URL with a line parameter (e.g., ?line=T1). The flow will validate this parameter and store the selected line for each user session. If the parameter is missing or invalid, the user will be redirected to a Not Found page.&lt;/p&gt;
&lt;p&gt;To achieve this, we need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the dashboard to expose client-specific metadata.&lt;/li&gt;
&lt;li&gt;Create a flow that validates the line parameter from the URL.&lt;/li&gt;
&lt;li&gt;Store the user’s selected line using session-aware context data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;configuring-dashboard-widgets-to-include-client-information&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#configuring-dashboard-widgets-to-include-client-information&quot;&gt;Configuring Dashboard Widgets to Include Client Information&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To ensure client data is available in your flows, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Dashboard 2.0&lt;/strong&gt; sidebar.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Client Data&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Enable the option &lt;strong&gt;“Include client data”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tick the checkbox in front of:
&lt;ul&gt;
&lt;li&gt;ui-control&lt;/li&gt;
&lt;li&gt;ui-template&lt;/li&gt;
&lt;li&gt;ui-button&lt;/li&gt;
&lt;li&gt;ui-text-input&lt;/li&gt;
&lt;li&gt;ui-dropdown&lt;/li&gt;
&lt;li&gt;ui-notification&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy&lt;/strong&gt; the updated configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Enabling client data in the Dashboard 2.0 settings to include metadata from specific widgets.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/client-data-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard 2.0 settings to include client metadata from selected widgets like buttons and templates.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With this setting enabled, the selected widgets will include client-related metadata in their output messages under the &lt;code&gt;msg._client&lt;/code&gt; property. This metadata is essential for building session-aware features in the Dashboard.&lt;/p&gt;
&lt;h4 id=&quot;building-a-dashboard-flow-for-url-access%2C-line-validation%2C-and-user-selection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#building-a-dashboard-flow-for-url-access%2C-line-validation%2C-and-user-selection&quot;&gt;Building a Dashboard Flow for URL Access, Line Validation, and User Selection&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this section, we&#39;ll build a Node-RED flow that handles dashboard access via direct URLs, validates the line parameter, and stores the selected line per user session using client metadata. This ensures that each user&#39;s line selection is tracked independently and that invalid or missing parameters are handled gracefully.&lt;/p&gt;
&lt;p&gt;The flow performs the following key tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Detects when a user accesses the dashboard using a URL containing a line parameter.&lt;/li&gt;
&lt;li&gt;Validates the parameter against a list of predefined production lines.&lt;/li&gt;
&lt;li&gt;Stores the selected line using session-aware (client-specific) data.&lt;/li&gt;
&lt;li&gt;Redirects the user appropriately based on the validity of the parameter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Steps to Build the Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui-event node&lt;/strong&gt; onto the canvas and configure it with the correct UI base path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;switch node&lt;/strong&gt; and name it &amp;quot;Is it a pageview event?&amp;quot; and configure it with the property &lt;code&gt;msg.topic&lt;/code&gt; and add the following condition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;== $pageview&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;switch node&lt;/strong&gt; and name it &amp;quot;Has line key?&amp;quot; and configure it with the property &lt;code&gt;msg.payload.page.params.line&lt;/code&gt;, with two conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;has key &lt;code&gt;line&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;is empty&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;ui-event node&lt;/strong&gt; to the first switch node (labeled Is it a pageview event?). Then, connect the first output of this switch node to the second switch node (labeled Has line key?). This checks whether the page was accessed via URL and if a line parameter is present.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;function&lt;/code&gt; node and name it &amp;quot;Extract Labels from Lines&amp;quot; and paste the following code:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-403&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-403&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lines &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lines&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; labels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;lines&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;labels &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; labels&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-403&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This retrieves the list of available lines from the persistent global context, extracts their labels, and creates an array for easier verification of whether the user selected line is present.&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; and name it &amp;quot;Store line selection&amp;quot;:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;global.store[msg._client.socketId].line&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Drag another &lt;strong&gt;switch node&lt;/strong&gt; and name it &amp;quot;Is the currently accessed page &#39;Lines&#39;?&amp;quot;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;is equal to &amp;quot;Lines&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;function node&lt;/strong&gt; (Extract Labels from Lines) and the &lt;strong&gt;change node&lt;/strong&gt; (Store line selection) to the first output of the &lt;strong&gt;switch node&lt;/strong&gt; (Has line key?).&lt;/li&gt;
&lt;li&gt;Drag another &lt;code&gt;switch&lt;/code&gt; node and name it &amp;quot;Is line valid?&amp;quot; and set the property to &lt;code&gt;msg.payload.labels&lt;/code&gt; and add following conditions:
&lt;ul&gt;
&lt;li&gt;contains &lt;code&gt;global.store[msg._client.socketId].line&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For the first output of the &lt;code&gt;switch&lt;/code&gt; node (Is the currently accessed page &#39;Lines&#39;?), drag a &lt;strong&gt;change&lt;/strong&gt; node and name it &amp;quot;Redirect the user to the All Lines menu&amp;quot; and Configure it to:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;&amp;quot;All Lines&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-control node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;change node&lt;/strong&gt; (Redirect the user to the All Lines menu). This node will handle the redirection or display feedback on the dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This checks whether the selected line is valid by comparing it with the list of known line labels.&lt;/p&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;For the second output of the switch node (Is line valid?), drag a switch node and give it name &amp;quot;Is the currently accessed page &#39;Lines&#39;?&amp;quot; and Set property to &lt;code&gt;msg.payload.page.name&lt;/code&gt; and add following condition to check against:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;== &amp;quot;Lines&amp;quot;&lt;/li&gt;
&lt;li&gt;Otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;For the first output of the switch node ((Is the currently accessed page &#39;Lines&#39;?), drag a change node and configure it to:
- Set &lt;code&gt;msg.payload&lt;/code&gt; to &amp;quot;Incorrect Link&amp;quot;&lt;/li&gt;
&lt;li&gt;Drag a ui-control node onto the canvas and configure it with the correct UI base path and connect it the change node (Redirect to Not found page).&lt;/li&gt;
&lt;li&gt;Deploy the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow for handling dashboard navigation, validating URL parameters, and assigning selected production lines to individual client sessions.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/accessing-production-lines.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow for managing URL-based access, validating line parameters, and storing client-specific selections on the OEE dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;create-live-request-flow-(per-line)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#create-live-request-flow-(per-line)&quot;&gt;Create Live Request Flow (Per Line)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s build the flow to retrieve the data now based on the user selection.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;Template&lt;/code&gt; widget onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the Template widget to open its configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the scope to &lt;code&gt;ui&lt;/code&gt; and select the appropriate UI Base.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following script into the content field. This script triggers every second and sends a message that includes the current user&#39;s client data:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-539&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-539&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Set an interval to update the message every second&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;intervalId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Component has loaded&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;beforeUnmount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Clear the interval when the component is about to be destroyed&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;intervalId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-539&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;Change&lt;/code&gt; node and name it &amp;quot;Set params&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the Change node with the following rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$line&lt;/code&gt; to &lt;code&gt;global.store[msg._client.socketId].line&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.query&lt;/code&gt; to &lt;code&gt;&amp;quot;line&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;Template&lt;/code&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the Template node and set the property to &lt;code&gt;msg.topic&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following SQL query into the content field:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-577&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-577&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; requests &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; resolved &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-577&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;Markdown&lt;/code&gt; widget and name it &amp;quot;Show currently selected line&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new group in the UI for the Markdown widget to render into.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the following content into the Markdown widget:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-593&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-593&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Line: &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-593&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dashboard view showing the title of the selected production line centered at the top.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/lines-page-with-tittle-of-selected-line.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The dashboard displays the selected production line name, retrieved from the client context, rendered using a Markdown widget.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Drag a &lt;code&gt;SQLite&lt;/code&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Select the appropriate database configuration.&lt;/li&gt;
&lt;li&gt;Set the node to use the SQL query via &amp;quot;Prepared Statement&amp;quot;.&lt;/li&gt;
&lt;li&gt;Connect the &lt;code&gt;Template&lt;/code&gt; widget to &lt;code&gt;Change&lt;/code&gt; node and &lt;code&gt;Template&lt;/code&gt; node to &lt;code&gt;SQLite&lt;/code&gt; node.&lt;/li&gt;
&lt;li&gt;Drag a &lt;code&gt;link-out&lt;/code&gt; node onto the canvas and connect it to the &lt;code&gt;SQLite&lt;/code&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED flow to fetch live requests for a selected production line using client context and SQLite query.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/retrive-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow that triggers periodic queries for open requests specific to the user’s selected line using the client session and a SQLite database.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;preparing-data-rendering-it-in-a-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#preparing-data-rendering-it-in-a-table&quot;&gt;Preparing Data Rendering it in a Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the data is retrieved, it needs to be validated, formatted, and routed appropriately for display. In this section, a flow will be built to check whether any unresolved requests exist for the selected production line. If there are no requests, a message will be shown to the user. Otherwise, the data will be processed and rendered in a table format using Dashboard widgets.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in node&lt;/strong&gt; onto the canvas and connect it to the last &lt;strong&gt;link-out node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;switch node&lt;/strong&gt; to check whether the &lt;code&gt;msg.payload&lt;/code&gt; is empty, name it &amp;quot;Is Payload empty?&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the switch with the following conditions:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;msg.payload is empty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Otherwise&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt;, name it &amp;quot;Show &#39;no outstanding request&#39; message&amp;quot; and configure it to set a message when the payload is empty:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;&amp;quot;There are no outstanding requests&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect this &lt;strong&gt;change node&lt;/strong&gt; to the first output of the switch node (&amp;quot;Is Payload empty?&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;change node&lt;/strong&gt;, name it &amp;quot;Remove &#39;no outstanding request&#39; message&amp;quot; and configure it as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to an empty string &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect this second &lt;strong&gt;change node&lt;/strong&gt; to the second output of the switch node (&amp;quot;Is Payload empty?&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;text widget&lt;/strong&gt;, name it &amp;quot;Text Widget for Message&amp;quot;, onto the canvas, double-click it, and add a new group in the &amp;quot;Lines&amp;quot; page to render the message.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;text widget&lt;/strong&gt; (&amp;quot;Text Widget for Message&amp;quot;) to both &lt;strong&gt;change nodes&lt;/strong&gt; that are setting the text message (&amp;quot;Show &#39;no outstanding request&#39; message&amp;quot; and &amp;quot;Remove &#39;no outstanding request&#39; message&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;link-out node&lt;/strong&gt; onto the canvas and connect it to the second output of the switch node (&amp;quot;Is Payload empty?&amp;quot;) that checks whether &lt;code&gt;msg.payload&lt;/code&gt; is empty.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;link-in&lt;/strong&gt; onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;split node&lt;/strong&gt;, name it &amp;quot;Split Node&amp;quot;, onto the canvas and connect it to the &lt;strong&gt;link-in node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-out node&lt;/strong&gt; and connect it to the &lt;strong&gt;split node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow that checks if unresolved requests exist, sends an appropriate message when none are found, or prepares the data for tabular rendering&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/preparing-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow that checks if unresolved requests exist, sends an appropriate message when none are found, or prepares the data for tabular rendering.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;setting-up-visual-alerts-and-timestamp-formatting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#setting-up-visual-alerts-and-timestamp-formatting&quot;&gt;Setting Up Visual Alerts and Timestamp Formatting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To enhance the visibility of production line requests, this section focuses on setting up visual alerts based on the age of each request and formatting timestamps in a user-friendly way. The created timestamp is always shown using relative time (e.g., &amp;quot;5 minutes ago&amp;quot;). For acknowledged and resolved, relative formatting is applied only when those timestamps are available. This improves readability and makes it easier to identify requests that are pending action.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in node&lt;/strong&gt; and a &lt;strong&gt;function node&lt;/strong&gt; onto the canvas. Name the &lt;strong&gt;function node&lt;/strong&gt; as &amp;quot;Highlight Old Requests&amp;quot; and open it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following JavaScript code into the &lt;strong&gt;function node&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-761&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-761&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requested &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requested&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requestedTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requested&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; difference &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; requestedTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; oldRequestThreshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;oldRequestThreshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; veryOldRequestThreshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;veryOldRequestThreshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alertActivationThreshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;alertActivationThreshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;difference &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;veryOldRequestThreshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;class &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;older&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;difference &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;alertActivationThreshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;difference &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;oldRequestThreshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;class &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;old&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;difference &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;alertActivationThreshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;difference &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;alertActivationThreshold &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;class &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;normal&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-761&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the link-in node to the function node.&lt;/li&gt;
&lt;li&gt;Drag a date time formatter node onto the canvas. Name it &amp;quot;Format Requested Time&amp;quot; and double-click it to configure.
&lt;ul&gt;
&lt;li&gt;Set outputFrom to fromNow.&lt;/li&gt;
&lt;li&gt;Set both input and output to &lt;code&gt;msg.payload.requested&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Connect the function node to the date time formatter node.&lt;/li&gt;
&lt;li&gt;Drag a link-out node and connect it to the function node.&lt;/li&gt;
&lt;li&gt;Drag a switch node onto the canvas. Name it &amp;quot;Check if Acknowledged is null&amp;quot;. Set the property to &lt;code&gt;msg.payload.acknowledged&lt;/code&gt;, and add the following conditions:
&lt;ul&gt;
&lt;li&gt;is null&lt;/li&gt;
&lt;li&gt;Otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Connect the function node to the switch node.&lt;/li&gt;
&lt;li&gt;Drag a second date time formatter node onto the canvas. Name it &amp;quot;Format Acknowledged Time&amp;quot;.
&lt;ul&gt;
&lt;li&gt;Set outputFrom to fromNow.&lt;/li&gt;
&lt;li&gt;Set both input and output to &lt;code&gt;msg.payload.acknowledged&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Connect the second date time formatter node to the second output of the switch node (&amp;quot;Check if Acknowledged is null&amp;quot;).&lt;/li&gt;
&lt;li&gt;Drag another switch node onto the canvas. Name it &amp;quot;Check if Resolved is null&amp;quot;. set the property to &lt;code&gt;msg.payload.resolved&lt;/code&gt;. Add the following conditions:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;is null&lt;/li&gt;
&lt;li&gt;Otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;Connect this switch node (&amp;quot;Check if Resolved is null&amp;quot;) to the output of the second date time formatter (&amp;quot;Format Acknowledged Time&amp;quot;) node and to the first output of the first switch node (&amp;quot;Check if Acknowledged is null&amp;quot;).&lt;/li&gt;
&lt;li&gt;Drag a third date time formatter node onto the canvas. Name it &amp;quot;Format Resolved Time&amp;quot; and set outputFrom to fromNow. Set both input and output to &lt;code&gt;msg.payload.resolved&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Connect this third date time formatter node to the second output of the second switch node (&amp;quot;Check if Resolved is null&amp;quot;) .&lt;/li&gt;
&lt;li&gt;Drag a link-out node and connect it to the third date time formatter node.&lt;/li&gt;
&lt;li&gt;Drag another link-out node and connect it to the first output of the second switch node. Name it &amp;quot;Link to First Switch Output&amp;quot;.&lt;/li&gt;
&lt;li&gt;Deploy the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dashboard view displaying a highlighted request entry with visual emphasis based on request age.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/highlighted-requst.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard showing a request visually highlighted based on how long ago it was made, with applied styling and alert classification.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED flow that includes nodes for assigning visual alert classes and formatting timestamps using relative time.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/visual-alert-and-timestamp-formatting.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow for setting visual alert classes and formatting timestamps like &amp;quot;5 minutes ago&amp;quot; to enhance clarity and urgency of displayed requests.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;highlight-requests-with-css-%26-add-buttons-to-update-request-status&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#highlight-requests-with-css-%26-add-buttons-to-update-request-status&quot;&gt;Highlight Requests with CSS &amp;amp; Add Buttons to Update Request Status&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have the data prepared, the class property added to each request message, and the timestamp formatted for better readability. In this section, we will add &lt;strong&gt;&#39;Resolve&#39;&lt;/strong&gt; and &lt;strong&gt;&#39;Acknowledge&#39;&lt;/strong&gt; buttons for each request to update its status and apply CSS classes based on the &lt;code&gt;status&lt;/code&gt; property for visual highlighting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in&lt;/strong&gt; node onto the canvas and connect it to the last &lt;strong&gt;link-out&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a switch node, name it &amp;quot;Is acknowledged null?&amp;quot;, and set the property to &lt;code&gt;msg.payload.acknowledged&lt;/code&gt;. Add the following conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is null&lt;/li&gt;
&lt;li&gt;otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;template node&lt;/strong&gt;, name it &lt;strong&gt;&amp;quot;Build ack link&amp;quot;&lt;/strong&gt;, set the property to &lt;code&gt;msg.payload.acknowledged&lt;/code&gt;, and add the following Mustache:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-928&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-928&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/dashboard/lines?line=&amp;amp;action=ack&amp;amp;request=&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;ACKNOWLEDGE&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-928&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;link-in&lt;/strong&gt; node to the &lt;strong&gt;switch&lt;/strong&gt; node. Connect the &lt;strong&gt;first output&lt;/strong&gt; of the switch node (&amp;quot;Is acknowledged null?&amp;quot;) to the input of the &lt;strong&gt;template&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another switch node, name it &amp;quot;Is resolved null?&amp;quot;, set the property to &lt;code&gt;msg.payload.resolved&lt;/code&gt;, and add the following conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is null&lt;/li&gt;
&lt;li&gt;otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;template node&lt;/strong&gt;, give it name &amp;quot;Build res link&amp;quot;,  set the property to &lt;code&gt;msg.payload.resolved&lt;/code&gt;, and add the following Mustache:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-956&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-956&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/dashboard/lines?line=&amp;amp;action=res&amp;amp;request=&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;RESOLVE&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-956&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the input of this second switch node (&amp;quot;Is resolved null?&amp;quot;) to the &lt;strong&gt;second output&lt;/strong&gt; of the previous switch node (&lt;code&gt;acknowledged&lt;/code&gt; switch), then connect the &lt;strong&gt;first output&lt;/strong&gt; of the &lt;code&gt;resolved&lt;/code&gt; switch node to the input of the second &lt;strong&gt;template&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-out&lt;/strong&gt; node and connect both outputs of the &lt;code&gt;resolved&lt;/code&gt; switch node to this link-out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding &#39;Acknowledged&#39; and &#39;Resolved&#39; buttons for each request in the table&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-request-update-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding action buttons to update the status of each request directly from the dashboard table.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;adding-a-mechanism-to-update-the-status-of-a-request-in-the-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#adding-a-mechanism-to-update-the-status-of-a-request-in-the-database&quot;&gt;Adding a Mechanism to Update the Status of a Request in the Database&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag &lt;strong&gt;ui event widget&lt;/strong&gt; onto the canvas and configure it with the correct ui base.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag &lt;strong&gt;change node&lt;/strong&gt; onto the canvas and add the following element:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$request&lt;/code&gt; to &lt;code&gt;msg.payload.query.request&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag &lt;strong&gt;Date/Time Formatter node&lt;/strong&gt; onto the canvas and set input format to &amp;quot;timestamp: milliseconds since epoch&amp;quot; and output to &lt;code&gt;msg.now&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag &lt;strong&gt;switch node&lt;/strong&gt; onto the canvas, set property to &lt;code&gt;msg.query.action&lt;/code&gt;, and add the following conditions to check against:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;== ack&lt;/li&gt;
&lt;li&gt;== res&lt;/li&gt;
&lt;li&gt;otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag two SQLite nodes onto the canvas, select the correct database configuration for both, and set the query type to &#39;Prepared Statement&#39;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the &lt;strong&gt;first&lt;/strong&gt;, set the following sql query:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-1039&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-1039&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; requests &lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; acknowledged &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $now&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; rowid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $request &lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; acknowledged &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-1039&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the &lt;strong&gt;second&lt;/strong&gt;, set the following sql query:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-1045&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-1045&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; requests &lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; resolved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $now&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; rowid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $request &lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; resolved &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-1045&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;ui event widget&lt;/strong&gt; to &lt;strong&gt;change node&lt;/strong&gt;, &lt;strong&gt;change node&lt;/strong&gt; to &lt;strong&gt;date/time formatter node&lt;/strong&gt;, &lt;strong&gt;date/time formatter&lt;/strong&gt; to &lt;strong&gt;switch node&lt;/strong&gt;, and:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;switch node first output&lt;/strong&gt; to first &lt;strong&gt;first sqlite node&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;switch node second output&lt;/strong&gt; to second &lt;strong&gt;second sqlite node&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow for the mechanism to update request status&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/update-request-status.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Flow that handles the update of request status based on user actions (Acknowledged or Resolved).&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;render-request-data-in-a-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#render-request-data-in-a-table&quot;&gt;Render Request Data in a Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&#39;s display the prepared data in a table. To do this, we&#39;ll use a &lt;strong&gt;ui_table&lt;/strong&gt; widget. However, before displaying, we need to convert the data back into an array, as we are currently spilling array data retrieved from the database into a single message.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;last link-out&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;join&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;link-in&lt;/strong&gt; node. Double-click on the join node and set the mode to &lt;strong&gt;automatic&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;link-out&lt;/strong&gt; node and connect it to the &lt;strong&gt;join&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in&lt;/strong&gt; node and connect it to the &lt;strong&gt;last link-out&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui_table&lt;/strong&gt; widget onto the canvas and double-click to configure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;strong&gt;new group&lt;/strong&gt; on the &lt;em&gt;lines&lt;/em&gt; page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;strong&gt;Action&lt;/strong&gt; to &lt;code&gt;replace&lt;/code&gt; and &lt;strong&gt;Interaction&lt;/strong&gt; to &lt;code&gt;none&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Untick the &lt;strong&gt;Auto Calculate Columns&lt;/strong&gt; option.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following column elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Key: rowid, Label: Request, Align: Left, Type: Text&lt;/li&gt;
&lt;li&gt;Key: line, Label: Line, Align: Left, Type: Text&lt;/li&gt;
&lt;li&gt;Key: support, Label: Support, Align: Left, Type: Text&lt;/li&gt;
&lt;li&gt;Key: requested, Label: Requested, Align: Left, Type: HTML&lt;/li&gt;
&lt;li&gt;Key: acknowledged, Label: Acknowledged, Align: Left, Type: HTML&lt;/li&gt;
&lt;li&gt;Key: resolved, Label: Resolved, Align: Left, Type: HTML&lt;/li&gt;
&lt;li&gt;Key: notes, Label: Notes, Align: Left, Type: Text&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Render Data on table&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/render-data-in-table.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Render Data on table.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;create-new-request-submission-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#create-new-request-submission-flow&quot;&gt;Create New Request Submission Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To create a flow that allows users to submit a request, follow these steps to set up the necessary UI elements, store the request details, validate input, and store the data in a database.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;ui-event&lt;/strong&gt; widget onto the canvas and configure it with the correct UI settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; to retrieve the department list and name it &amp;quot;Show Dropdown Options&amp;quot;. Add the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.ui_update.options&lt;/code&gt; to &lt;code&gt;global.departments&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new group for the dropdown widget on the lines page. Connect the &lt;strong&gt;change node&lt;/strong&gt; to the input of the dropdown widget, then link it to the &lt;strong&gt;ui-event&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;change node&lt;/strong&gt; and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.store[msg._client.socketId].support&lt;/code&gt;. Name it &amp;quot;Store support (department) to context store&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;text input widget&lt;/strong&gt; for the notes field. Create a group for it in the lines page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add another &lt;strong&gt;change node&lt;/strong&gt; to store the notes in the global context and name it &amp;quot;Store notes to context store&amp;quot;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.store[msg._client.socketId].notes&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node (&amp;quot;Store support (department) to context store&amp;quot;) to the input of the dropdown widget and connect the change node (&amp;quot;Store notes to context store&amp;quot;) to the text input widget.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;button widget&lt;/strong&gt;, label it &amp;quot;Request Support,&amp;quot; and connect it to the &lt;strong&gt;change node&lt;/strong&gt; that updates the UI with the department list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;change node&lt;/strong&gt; to store the request details in the global context and name it &amp;quot;Retrieve entered support request data&amp;quot;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.request&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.request.support&lt;/code&gt; to the value &lt;code&gt;msg.store[msg._client.socketId].support&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.request.notes&lt;/code&gt; to the value &lt;code&gt;msg.store[msg._client.socketId].notes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.request.line&lt;/code&gt; to the value &lt;code&gt;msg.store[msg._client.socketId].line&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.request.reference&lt;/code&gt; to the value &lt;code&gt;msg.store[msg._client.socketId].reference&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the switch node onto the canvas and set property to &lt;code&gt;msg.request&lt;/code&gt; and add condtion to check &amp;quot;is not null&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;function node&lt;/strong&gt; and add the following code. Name it &amp;quot;Does department and notes are not empty?&amp;quot;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-1270&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-1270&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; request &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; request &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; request &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Request must be an object.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;support&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Please select the appropriate department for the request.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;notes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Please add notes to provide more context on the request.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-1270&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node to switch node and switch node to function node. Connect the function node&#39;s first output to a &lt;strong&gt;Date/Time Formatter&lt;/strong&gt; node. Set the input to &#39;Timestamp (milliseconds since epoch)&#39; and the output to &lt;code&gt;msg.request.time&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; and set &lt;code&gt;msg.payload&lt;/code&gt; to &amp;quot;Are you sure you want to submit a request?&amp;quot;. Name it &amp;quot;Set Confirmation message&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node (&amp;quot;Set Confirmation message&amp;quot;) to the &lt;strong&gt;Date/Time Formatter&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui-notification widget&lt;/strong&gt;, configure it with the correct UI, and set the position to center, checked the checkbox for both allow mnaual dismisal and all amnual confirmation, change close to &amp;quot;Cancel&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node (&amp;quot;Set Confirmation message&amp;quot;) to the &lt;strong&gt;ui-notification&lt;/strong&gt; widget.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;ui-notification widget&lt;/strong&gt;, configure it with the correct UI, and set the position to center.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;connect it to the second output of the function node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;strong&gt;switch node&lt;/strong&gt; and set the property to &lt;code&gt;msg.payload&lt;/code&gt; with the condition:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;== &lt;code&gt;confirm_clicked&lt;/code&gt;
Name it &amp;quot;Is confirm clicked?&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;20&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; and add the following elements and give it name &amp;quot;Set Params&amp;quot;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$line&lt;/code&gt; to the value &lt;code&gt;msg.request.linet&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$support&lt;/code&gt; to the value &lt;code&gt;msg.request.support&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$time&lt;/code&gt; to the value &lt;code&gt;msg.request.time&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$notes&lt;/code&gt; to the value &lt;code&gt;msg.request.notes&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;21&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the change node (&amp;quot;Set Params&amp;quot;) to the switch node (&amp;quot;Is confirm clicked?&amp;quot;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;sqlite node&lt;/strong&gt;, select the correct database configuration, and choose SQL Query via &amp;quot;Prepared Statement&amp;quot; and connect that sqlite node to the input change node (&amp;quot;Set Params&amp;quot;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; and set the following, give it name &amp;quot;Clear entered request data&amp;quot;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Delete &lt;code&gt;msg.store[msg._client.socketId].support&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Delete &lt;code&gt;msg.store[msg._client.socketId].notes&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;24&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;change node&lt;/strong&gt;* (&amp;quot;Clear entered request data&amp;quot;) to the &lt;strong&gt;sqlite node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-out node&lt;/strong&gt; and connect it to the last change node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link-in node&lt;/strong&gt; and connect it to the last link-out node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag two &lt;strong&gt;change nodes&lt;/strong&gt; and configure them as follows:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;First change node: Set &lt;code&gt;msg.payload&lt;/code&gt; to an empty array &lt;code&gt;[]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Second change node: Set &lt;code&gt;msg.payload&lt;/code&gt; to an empty string &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;28&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the change nodes to the link-in node to complete the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the first change node to the &lt;strong&gt;ui dropdown widget&lt;/strong&gt; and the second to the &lt;strong&gt;text input widget&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED flow showing the logic for validating and storing user-submitted support requests.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/submit-request-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Node-RED flow to handle request submission, including form validation, timestamp formatting, and SQL database insertion.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We have now successfully built one part of the Andon task dashboard. You can open the line view in the dashboard and check whether you can submit a request, mark it as acknowledged, and resolve it.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;UI form with dropdown, text input, and a submit button labeled &amp;quot;Request Support.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/submit-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard UI where users select a department, enter notes, and submit a support request for the production line.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/building-andon-task-manager-dashboard-with-ff/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Up until now, the focus has been on building the core functionality of the Andon Task Manager dashboard, including the Lines page. Design and layout have not been the priority. In the next part, you will learn how to enhance the visual design, improve usability, and create a dedicated page and menu for departments.&lt;/p&gt;
&lt;p&gt;Later, we will guide you through building the Admin page for the Andon Task Manager dashboard—enabling request management, department configuration, and overall system control.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/</id>
        <title>What to Measure on the Shop Floor: Factory KPIs Your MES Should Deliver</title>
        <summary>From shop floor data to strategic advantage</summary>
        <updated>2025-06-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;When discussing an &lt;a href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/&quot;&gt;MES&lt;/a&gt;, data is always at the core. In previous articles, we explored the crucial steps of collecting and structuring valuable operational data. However, merely having cleaned and structured data is not enough. Many manufacturers find themselves staring at thousands of records while trying to monitor equipment performance or track production, only to feel overwhelmed and unsure of what actions to take. This is not just time-consuming; it often leads to delayed decisions and missed opportunities.&lt;/p&gt;
&lt;p&gt;It is not the volume of data that drives improvement, it is clarity. What manufacturers need is a way to cut through the noise and highlight what truly matters. Factory KPIs (Key Performance Indicators) do exactly that. By focusing attention on the metrics that reflect performance and progress, they turn complexity into clarity and enable faster, more confident decisions.&lt;/p&gt;
&lt;p&gt;In this article, we will dive into the most critical factory KPIs that directly impact your bottom line and are a fundamental part of any effective MES implementation. These KPIs empower you to drive profit and eliminate waste.&lt;/p&gt;
&lt;h2 id=&quot;strategic-kpi-categories-for-mes-success&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#strategic-kpi-categories-for-mes-success&quot;&gt;Strategic KPI Categories for MES Success&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are hundreds of factory KPIs available, but not all are relevant for every MES implementation. To effectively leverage MES and improve factory operations, it is important to organize KPIs into logical categories that support its core objectives. These categories provide a holistic view of factory performance and align operational data with key manufacturing goals.&lt;/p&gt;
&lt;p&gt;While many KPIs can be tracked, the most impactful ones in the context of MES typically fall into the following strategic categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Productivity&lt;/strong&gt;: Measuring the efficiency and output of production lines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processes&lt;/strong&gt;: Assessing how reliably the production chain functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deadlines&lt;/strong&gt;: Tracking time-related performance metrics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inventory Management&lt;/strong&gt;: Ensuring materials and products flow smoothly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt;: Evaluating equipment reliability and effectiveness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality&lt;/strong&gt;: Measuring consistency, conformance, and product standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;key-factory-kpis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#key-factory-kpis&quot;&gt;Key Factory KPIs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here are some of the most crucial KPIs your &lt;strong&gt;MES&lt;/strong&gt; should help you track:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;KPIs Tables&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/KPIs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;KPIs Tables&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;turning-your-data-into-kpis&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#turning-your-data-into-kpis&quot;&gt;Turning Your Data into KPIs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand the critical factory KPIs, the next logical question is: How does your MES deliver these insights? It’s not about manual calculations or picking up a calculator. The MES should have an integrated pipeline that handles everything—from raw data collection to the clear, actionable KPIs displayed on your dashboards.&lt;/p&gt;
&lt;p&gt;Once the data is collected and stored from the factory floor, this pipeline involves four essential stages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Retrieve Data&lt;/strong&gt;: Pull the necessary stored data from the central database to perform KPI calculations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Logic&lt;/strong&gt;: Define the rules, conditions, and formulas based on operational goals and KPI definitions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calculate KPIs&lt;/strong&gt;: Execute real-time or scheduled computations to derive metric values from the retrieved data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualize&lt;/strong&gt;: Display the results using dashboards to provide clear insights for operators, supervisors, and decision-makers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the workflow is set up, it should run automatically in the background—pulling in fresh data, applying the logic, and updating dashboards in real time. This ensures that performance metrics are always current and actionable.&lt;/p&gt;
&lt;h3 id=&quot;building-kpi-workflow-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#building-kpi-workflow-with-flowfuse&quot;&gt;Building KPI Workflow with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To turn stored factory data into live KPIs, you need a solution with a powerful logic engine capable of processing at scale. Ideally, this solution should also support the rapid development of industrial applications. This is where &lt;strong&gt;FlowFuse&lt;/strong&gt;, built on &lt;strong&gt;Node-RED&lt;/strong&gt;, offers a clear advantage.&lt;/p&gt;
&lt;p&gt;FlowFuse provides a low-code environment that unifies data connectivity, processing logic, and visualization. As covered in our previous articles—&lt;a href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/&quot;&gt;MES Data Acquisition: How to Unlock Your Factory’s Hidden Data&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/&quot;&gt;Structuring and Storing Data for Effective MES Integration&lt;/a&gt;—FlowFuse connects seamlessly to nearly all shop floor assets, prepares the data, and stores it in an accessible format.&lt;/p&gt;
&lt;p&gt;From there, KPI logic flows can be built visually, defining how and when data is retrieved, how calculations are applied, and how results are displayed. This enables continuous KPI updates without manual effort.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard built with FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;OEE Dashboard built with FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The example above shows an &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;OEE Dashboard&lt;/a&gt;, updated every 10 seconds using FlowFuse. Operational data is automatically retrieved, processed, and visualized, delivering accurate, real-time metrics through gauges, charts, and tables.&lt;/p&gt;
&lt;p&gt;The following flow powers this dashboard:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;OEE Dashboard Flow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Each node in this flow performs a specific task: retrieving data, transforming it, applying OEE formulas, and delivering results to the dashboard. The entire process is automated and repeatable, providing a real-time view of equipment performance and production health.&lt;/p&gt;
&lt;h4 id=&quot;build-your-first-kpi-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#build-your-first-kpi-flow&quot;&gt;Build Your First KPI Flow&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s see how easy it is to calculate a KPI with a practical example where we will calculate &lt;strong&gt;Machine Downtime&lt;/strong&gt;, using demo data stored in an SQLite database.&lt;/p&gt;
&lt;h5 id=&quot;to-begin&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#to-begin&quot;&gt;To Begin&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Login to the FlowFuse platform. If you don&#39;t have an account, you can register for a &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; to get started. Once registered, create a FlowFuse instance and open its editor.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;node-red-node-sqlite&lt;/code&gt; from the Palette Manager.&lt;/li&gt;
&lt;li&gt;For the demo database, import the following database flow. Upon deployment, it will create an SQLite table and insert the demo data:&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-225&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow225 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2b80c9ff5297fcf0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:1540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0e3ad13c7f083c30&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a0a5bf61836aaaba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 6&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1160,&#92;&quot;y&#92;&quot;:1540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e3ad13c7f083c30&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;0710931c9543fc07&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;CREATE TABLE machine_runtime_logs (&#92;&#92;n    id INTEGER PRIMARY KEY AUTOINCREMENT,&#92;&#92;n    machine_id TEXT NOT NULL,&#92;&#92;n    date DATE NOT NULL,&#92;&#92;n    total_operational_time INTEGER NOT NULL,  -- in minutes, e.g., shift duration or planned availability&#92;&#92;n    run_time INTEGER NOT NULL                 -- in minutes, actual machine active time&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create &#39;machine_runtime_logs&#39; table&#92;&quot;,&#92;&quot;x&#92;&quot;:910,&#92;&quot;y&#92;&quot;:1540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a0a5bf61836aaaba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9b8478110727f43&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:1620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;65e503477a2e5349&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;65e503477a2e5349&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;0710931c9543fc07&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;INSERT INTO machine_runtime_logs (machine_id, date, total_operational_time, run_time) VALUES&#92;&#92;n(&#39;BX02&#39;, &#39;2025-06-10&#39;, 480, 410),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-10&#39;, 480, 465),&#92;&#92;n(&#39;BX02&#39;, &#39;2025-06-11&#39;, 480, 400),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-12&#39;, 480, 455),&#92;&#92;n(&#39;BX02&#39;, &#39;2025-06-12&#39;, 480, 390),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-11&#39;, 480, 470),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-13&#39;, 480, 460),&#92;&#92;n(&#39;BX02&#39;, &#39;2025-06-13&#39;, 480, 420),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-14&#39;, 480, 405),&#92;&#92;n(&#39;AX01&#39;, &#39;2025-06-14&#39;, 480, 450);&#92;&#92;n&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert Demo Data&#92;&quot;,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:1620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;45f1950b01ebb3f3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;45f1950b01ebb3f3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 7&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1160,&#92;&quot;y&#92;&quot;:1620,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0710931c9543fc07&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlitedb&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;/tmp/sqlite&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;RWC&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow225.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-225&#39;) })&lt;/script&gt;
&lt;h5 id=&quot;flow-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#flow-setup&quot;&gt;Flow Setup&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and configure it to trigger at your desired interval (e.g., every 10 seconds) to start the data retrieval process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node and connect it to the Inject node, adding elements to include query parameters for sql query as shown in the following image.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node setting parameters&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/params-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node setting parameters&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag an &lt;strong&gt;SQLite&lt;/strong&gt; node, connect it to the Change node, and configure it with following sql statement and select set query to &amp;quot;Prepared Statement&amp;quot;&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-172&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-172&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; machine_runtime_logs&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; machine_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $machine_id&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $start_date &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $end_date&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-172&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node and connect it to the SQLite node to break down the returned array or multiple rows from the database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag &lt;strong&gt;two Join&lt;/strong&gt; nodes and connect them to the output of the Split node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the &lt;strong&gt;first Join&lt;/strong&gt; node in &lt;em&gt;Reduce&lt;/em&gt; mode to sum &lt;code&gt;total_operational_time&lt;/code&gt; using the expression &lt;code&gt;$A + payload.total_operational_time&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the &lt;strong&gt;second Join&lt;/strong&gt; node in &lt;em&gt;Reduce&lt;/em&gt; mode to sum &lt;code&gt;run_time&lt;/code&gt; using the expression &lt;code&gt;$A + payload.run_time&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node and connect it to the first Join node to store &lt;code&gt;msg.payload&lt;/code&gt; as &lt;code&gt;flow.total_operational_time&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node and connect it to the second Join node to store &lt;code&gt;msg.payload&lt;/code&gt; as &lt;code&gt;flow.run_time&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;new Change&lt;/strong&gt; node and connect both previous Change nodes to it, then set &lt;code&gt;msg.payload&lt;/code&gt; using the following JSONata expression to calculate Machine Downtime Percentage:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;(($flowContext(&amp;quot;total_operational_time&amp;quot;) - $flowContext(&amp;quot;run_time&amp;quot;)) / $flowContext(&amp;quot;total_operational_time&amp;quot;)) * 100
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas, connect it to the last Change node, and configure it to display &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deploy&lt;/strong&gt; the flow to continuously calculate and output the Machine Downtime Percentage in real time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After deploying the flow, observe the debug sidebar on the right. You&#39;ll see the calculated machine downtime percentage being continuously printed. To present this data visually, leverage &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Flowfuse Dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Downtime printed on debug panel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/downtime.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Downtime printed on debug panel&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You’ve just seen how easy it is to calculate a foundational KPI like machine downtime. But with FlowFuse’s low-code environment, this is just the beginning. You not only connect, collect, transform, and visualize data—but also scale effortlessly.&lt;/p&gt;
&lt;p&gt;FlowFuse enables you to manage thousands of device instances remotely, with built-in security, access control, and version management. This level of control ensures consistency across your factory operations and allows you to deploy updates and changes quickly with confidence.&lt;/p&gt;
&lt;p&gt;There is much more to explore—FlowFuse gives you the flexibility and power to build a fully integrated, intelligent MES solution that grows with your manufacturing needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does this mean for your factory?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&#39;ll put more money in your pocket, by slashing hidden waste and squeezing every drop of efficiency out of your machines and time.&lt;/li&gt;
&lt;li&gt;You&#39;ll be in total control, ditching the daily firefighting for a clear view that lets you fix problems before they even start.&lt;/li&gt;
&lt;li&gt;You&#39;ll produce quality you&#39;re genuinely proud of, every single time, catching issues on the spot for fewer headaches and happier customers.&lt;/li&gt;
&lt;li&gt;You&#39;ll unleash the genius of your own team, giving them the insights they need to innovate and drive continuous improvement on the floor.&lt;/li&gt;
&lt;li&gt;You&#39;ll leap into tomorrow&#39;s factory, today, rapidly building powerful solutions that make your entire operation smarter, faster, and truly future-ready.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;final-thought&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/shop-floor-kpis-for-mes/#final-thought&quot;&gt;Final Thought&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve talked a lot about Factory KPIs and how they&#39;re not just some numbers on a screen; they&#39;re your secret weapon. And we&#39;ve seen how a powerful MES, especially one built on something as flexible as FlowFuse, is the real workhorse, taking all that raw data and turning it into clear, actionable gold.&lt;/p&gt;
&lt;p&gt;Forget about guessing games. With the right MES and smart KPIs, you get the full picture, right now. It means knowing what is happening on your floor, fixing issues fast, and making decisions that drive measurable impact.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Schedule a demo&lt;/a&gt; and we&#39;ll show you how FlowFuse transforms your operations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/</id>
        <title>Structuring and Storing Data for Effective MES Integration</title>
        <summary>Making Factory Data Tell the Right Story for Your MES</summary>
        <updated>2025-06-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Collecting factory data for your MES is just the first step. If that data isn&#39;t properly organized, cleaned, and stored, it&#39;s a jumbled mess, leading to missed opportunities and wasted investments. Disorganized information prevents your MES from quickly finding, understanding, and comparing crucial data, directly impacting production, increasing errors, and hindering confident decision-making.&lt;/p&gt;
&lt;p&gt;FlowFuse simplifies &lt;a href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/&quot;&gt;live factory data acquisition&lt;/a&gt;, and now it&#39;s time to make that data work harder. This article dives into best practices for structuring and storing factory data, helping you maximize your MES&#39;s performance and turn raw information into a powerful tool.&lt;/p&gt;
&lt;h2 id=&quot;core-strategies-for-structuring-your-factory-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#core-strategies-for-structuring-your-factory-data&quot;&gt;Core Strategies for Structuring Your Factory Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we understand the importance of data structuring, let&#39;s explore how to achieve it. This involves giving your data a clear shape and defining rules, ensuring that every system, that is part of your MES, can easily interpret the meaning of each piece of information.&lt;/p&gt;
&lt;p&gt;Here are some straightforward ways we get data structred:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Making a Plan for Your Data (Data Modeling):&lt;/strong&gt; This is like drawing a simple map for your data. It helps you decide exactly what pieces of information you&#39;ll collect (like machine temperature, how many items are made, or who operated the machine) and how they connect to each other. This keeps everything neat and consistent. For example, a data model might say that every &amp;quot;production run&amp;quot; must have a &amp;quot;start time&amp;quot; and an &amp;quot;end time.&amp;quot; This makes sure your MES always gets the full picture and avoids confusing or incomplete information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Speaking the Same Language (Standardizing):&lt;/strong&gt; Imagine if everyone in your factory used different words for the same thing. It would be confusing! Standardizing means always using the same names, units, and formats everywhere. For example, if you measure temperature, always use Celsius. If one machine sends &amp;quot;TempC&amp;quot; and another just &amp;quot;Temperature,&amp;quot; standardizing ensures both are read as &amp;quot;Temperature in Celsius.&amp;quot; This prevents your MES from getting confused by different terms for the same data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adding the Full Story (Contextulization):&lt;/strong&gt; A raw number like &amp;quot;100&amp;quot; by itself doesn&#39;t tell you much. But if you add &amp;quot;100 items made by Machine A on June 10th at 2:00 PM in Batch 123,&amp;quot; suddenly you know the whole story! This means attaching important details like the exact time, the machine&#39;s name, the batch number, or who was working at that moment. This extra information makes raw numbers meaningful, so your MES can track things accurately and you can make smarter decisions based on the full picture.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-flowfuse-brings-your-data-strategy-to-life&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#how-flowfuse-brings-your-data-strategy-to-life&quot;&gt;How FlowFuse Brings Your Data Strategy to Life&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse simplifies data structuring with its intuitive, drag-and-drop environment. Raw machine data—often just numeric signals—can be enriched, formatted, and organized in real time, &lt;strong&gt;without writing any code&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can easily:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add timestamps to readings&lt;/li&gt;
&lt;li&gt;Associate data with specific machines or lines&lt;/li&gt;
&lt;li&gt;Convert units (e.g., Fahrenheit to Celsius)&lt;/li&gt;
&lt;li&gt;Rename fields for consistency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse comes with standard nodes, like &lt;code&gt;split&lt;/code&gt;, &lt;code&gt;change&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;, and &lt;code&gt;switch&lt;/code&gt;. These let you visually tell FlowFuse how to transform your data. These nodes handle all the technical work for you. You just connect the blocks that clean your data, add context, and prepare it for use in monitoring dashboards or other industrial applications.&lt;/p&gt;
&lt;p&gt;There&#39;s another simple and powerful node to tell you about. It lets you handle data modeling, standardization, and contextualization, plus it checks your data to make sure it&#39;s in the correct range or type. We call this method JSON Schema validation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;JSON Schema&lt;/strong&gt; is a vocabulary that allows you to annotate and validate JSON documents. It defines the structure, data types, and validation rules, ensuring consistency and interoperability across different applications and systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;setting-up-json-schema-validation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#setting-up-json-schema-validation&quot;&gt;Setting Up JSON Schema Validation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get started, open your &lt;strong&gt;FlowFuse instance editor&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Next, you&#39;ll need to install the specific node for JSON Schema validation. Search for and install &lt;code&gt;node-red-contrib-json-full-schema-validator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the node is installed, your next step is to &lt;strong&gt;plan your data schema&lt;/strong&gt;. This involves deciding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Which properties are essential&lt;/strong&gt; for your data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What data types&lt;/strong&gt; these properties should have (e.g., number, string, boolean).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The units&lt;/strong&gt; for numerical data (e.g., if it&#39;s temperature, should it be Celsius or Fahrenheit?).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Valid ranges&lt;/strong&gt; for your data (e.g., a temperature range of -40°C to 150°C).&lt;/li&gt;
&lt;li&gt;Other factors like &lt;strong&gt;precision&lt;/strong&gt;, &lt;strong&gt;mandatory fields&lt;/strong&gt;, and any &lt;strong&gt;additional attributes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After planning, you&#39;ll prepare this schema in &lt;strong&gt;JSON format&lt;/strong&gt;. For a comprehensive guide on how to define your JSON Schemas, check out this helpful: &lt;a href=&quot;https://json-schema.org/learn/getting-started-step-by-step&quot;&gt;Getting Started Guide&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-116&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-116&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydraulic Pump&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pressure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;date-time&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Timestamp of when the data was recorded.&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The temperature value.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;minimum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The unit of the temperature value.&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;pressure&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The pressure value.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;minimum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;enum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Pascal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The unit of the pressure value.&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-116&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This JSON schema defines the structure for data related to a hydraulic pump. It includes three key properties: &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;temperature&lt;/code&gt;, and &lt;code&gt;pressure&lt;/code&gt;. The &lt;code&gt;timestamp&lt;/code&gt; must be in a valid date-time format. Both &lt;code&gt;temperature&lt;/code&gt; and &lt;code&gt;pressure&lt;/code&gt; require two properties: value (a number representing the actual measurement) and &lt;code&gt;unit&lt;/code&gt; (which must be Celsius for &lt;code&gt;temperature&lt;/code&gt; and Pascal for &lt;code&gt;pressure&lt;/code&gt;). Both values must be greater than or equal to zero. This schema ensures that all data is recorded with the correct units and valid values, maintaining consistency and reliability.&lt;/p&gt;
&lt;h3 id=&quot;implementing-data-schema-validation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#implementing-data-schema-validation&quot;&gt;Implementing Data Schema Validation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s implement the data schema validation mechanism to ensure each incoming data adheres to the specified JSON schema.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;JSON Full Schema Validator&lt;/strong&gt; node onto the Node-RED canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its settings.&lt;/li&gt;
&lt;li&gt;Copy and paste your schema into the node’s schema field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring &amp;quot;JSON Full Schema Validator&amp;quot; node with JSON schema for our data &quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/json-full-validator-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring &amp;quot;JSON Full Schema Validator&amp;quot; node with JSON schema for our data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the changes.&lt;/li&gt;
&lt;li&gt;Connect the input of the &lt;strong&gt;JSON Full Schema Validator&lt;/strong&gt; node to the data source from where your data is coming.&lt;/li&gt;
&lt;li&gt;Connect the node&#39;s first output to another node to process or handle the validated data (e.g., an MQTT node, a database node, or any other destination).&lt;/li&gt;
&lt;li&gt;Connect the second output to the flow that will handle the situation where data does not meet the schema. This could be a notification flow sending an email or Telegram to your team or a dashboard alert.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, let&#39;s understand this with an example. Below is the data that we are receiving from the PLC. After transforming it, we’ve added essential properties such as unit and value. However, notice that the data doesn&#39;t meet the schema definition because the temperature is given in Fahrenheit and is a negative number, which isn&#39;t within the expected range.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Message passes through the second output and includes errors when it does not align with the data schema.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/invalid-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Message passes through the second output and includes errors when it does not align with the data schema.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If the data doesn&#39;t align with the data schema, it will pass through the &amp;quot;JSON Full Schema Validator&amp;quot; node and flow through the second output. The message will contain an error array with detailed information about what is wrong with the data (e.g., incorrect unit or out-of-range value). From this output, you can easily connect email or Telegram nodes to send alert notifications.&lt;/p&gt;
&lt;p&gt;When the data meets the schema, it passes through the first output without errors. The validated data is then sent to the next stage in the flow.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Message passes through the first output and does not include errors when it aligns with the data schema.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/valid-data-message.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Message passes through the first output and does not include errors when it aligns with the data schema.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;where-to-keep-all-that-factory-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#where-to-keep-all-that-factory-data&quot;&gt;Where to Keep All That Factory Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once your factory data is structured and validated, you need a smart place to store it. Different kinds of information often require different storage types to be most useful for your MES.&lt;/p&gt;
&lt;p&gt;Here are the main types of storage typically used for factory data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time-Series Databases (TSDBs):&lt;/strong&gt; Perfect for constantly changing data like sensor readings (temperature, machine speed). They handle massive updates efficiently, ideal for spotting trends over time. Think of them as a super-efficient diary recording every moment. &lt;strong&gt;InfluxDB&lt;/strong&gt; and &lt;strong&gt;TimescaleDB&lt;/strong&gt; are good examples.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Standard Databases (SQL Databases):&lt;/strong&gt; Best for structured information with clear connections, such as production orders, material usage per batch, or quality check results. They keep data organized and ensure correct links between pieces of information, like a well-organized spreadsheet. You&#39;ll often see &lt;strong&gt;PostgreSQL&lt;/strong&gt; or &lt;strong&gt;MySQL&lt;/strong&gt; used here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Lakes or Cloud Storage:&lt;/strong&gt; Use these for vast amounts of diverse data, even if it&#39;s not perfectly organized. They&#39;re great for long-term historical records or data you&#39;ll analyze later with advanced tools. Imagine them as a huge warehouse for anything, ready when you need to sort through it. &lt;strong&gt;Amazon S3&lt;/strong&gt; and &lt;strong&gt;Azure Data Lake Storage&lt;/strong&gt; are common examples.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When choosing storage, consider your data volume and speed, how often you need to access it (real-time vs. historical), cost, scalability, system connectivity, and data security.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-also-helps-with-data-routing-to-storage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#flowfuse-also-helps-with-data-routing-to-storage&quot;&gt;FlowFuse Also Helps with Data Routing to Storage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse isn&#39;t just for changing and cleaning data; it also makes sure your data gets to the right storage spot.&lt;/p&gt;
&lt;p&gt;It has tons of nodes for almost every database and cloud storage system you&#39;ll find in a factory today.&lt;/p&gt;
&lt;p&gt;This includes direct &lt;strong&gt;connections&lt;/strong&gt; to normal databases like &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-mysql&quot;&gt;MySQL&lt;/a&gt; and &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-postgresql&quot;&gt;PostgreSQL&lt;/a&gt; for your organized production data.&lt;/p&gt;
&lt;p&gt;It also has special nodes for time-series databases like &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-influxdb&quot;&gt;InfluxDB&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/node-red/database/timescaledb/&quot;&gt;TimescaleDB&lt;/a&gt; to handle fast sensor and machine data.&lt;/p&gt;
&lt;p&gt;Plus, FlowFuse &lt;strong&gt;connects&lt;/strong&gt; to big Data Lakes and Cloud Storage services like &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-aws&quot;&gt;Amazon S3&lt;/a&gt;, &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-google-cloud&quot;&gt;Google Cloud Storage&lt;/a&gt;, and &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-azure-storage&quot;&gt;Microsoft Azure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse Fuels Your MES Dashboards and Applications&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once your factory data is effectively structured, validated, and routed by FlowFuse to the right place, it becomes an incredibly powerful asset for your MES.&lt;/p&gt;
&lt;p&gt;FlowFuse doesn&#39;t just manage your data; it also empowers you to easily build the user interface (UI) for your MES. You can create insightful dashboards and industrial applications using a no-code, drag-and-drop approach with components from &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt;. This allows you to design the screens operators use to visualize critical information and control processes, all built upon the reliable data foundation you&#39;ve established.&lt;/p&gt;
&lt;h2 id=&quot;final-thought&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/structuring-storing-data-mes-integration/#final-thought&quot;&gt;Final Thought&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your factory&#39;s success hinges on smart decisions, and smart decisions need good data. It&#39;s not enough to just collect information from your machines; you need to make sense of it.&lt;/p&gt;
&lt;p&gt;That means organizing your data so it&#39;s clear and consistent. Think of it like putting all your tools in the right place – easy to find when you need them. You also need to clean up the data, getting rid of errors so you can trust what you see. Finally, you need to store it smartly, choosing the best spot for different types of information so it&#39;s always ready for use.&lt;/p&gt;
&lt;p&gt;FlowFuse helps with all of this. It&#39;s like your data&#39;s personal assistant, collecting raw information, tidying it up, and sending it to the right storage, all without complicated coding. This ensures your Manufacturing Execution System (MES) gets the accurate, reliable data it needs to help you run your factory smoother and make better choices. Hundreds of other manufacturing companies are already using FlowFuse to transform their data into a powerful asset.&lt;/p&gt;
&lt;p&gt;If you want to see FlowFuse in action, &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt; today!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/</id>
        <title>MES Data Acquisition: How to Unlock Your Factory’s Hidden Data</title>
        <summary>Breaking Down Data Silos to Empower Your MES</summary>
        <updated>2025-06-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A Manufacturing Execution System (MES) is the central control system of a factory. To work properly, it needs a steady stream of real-time data from machines and systems on the factory floor. This data is essential for running operations smoothly. But in most factories, the hardest part is getting this data to the MES.&lt;/p&gt;
&lt;p&gt;This article dives into the data that fuels your MES and the complex web of sources it comes from. We&#39;ll explore the core challenge that keeps this data locked away in silos. Most importantly, we’ll show how &lt;strong&gt;FlowFuse&lt;/strong&gt; acts as the catalyst to liberate this data, empowering you to get the right information to your MES, exactly when and where you need it most.&lt;/p&gt;
&lt;h2 id=&quot;the-operational-data-your-mes-needs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/#the-operational-data-your-mes-needs&quot;&gt;The Operational Data Your MES Needs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a factory&#39;s main computer system (the MES) to do its job, it needs a constant stream of information. Think of it like a control room that needs to see everything at once. This information can be grouped into four main types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Production Information:&lt;/strong&gt; This tells the system how much is being made, how fast it&#39;s being made, and if any products had to be thrown out. It&#39;s the basic &amp;quot;are we winning?&amp;quot; data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Machine Information:&lt;/strong&gt; This is like a live health report for your equipment. It tells the system if a machine is running or stopped, what its settings are (like temperature or speed), and how much power it&#39;s using.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Context and Quality Information:&lt;/strong&gt; This data adds the &amp;quot;why.&amp;quot; It tells the system who is working, why a machine stopped, and if the products being made are good enough to sell.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Material Information:&lt;/strong&gt; This tells the full story of a product. It tracks all the raw materials and parts from start to finish, so you know exactly what went into every single item.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the system gets all this information, it does more than just track numbers. It becomes the factory&#39;s control center. It gives workers step-by-step instructions on their screens, makes sure rules are followed to prevent mistakes, and lets managers see exactly what’s happening everywhere so they can fix small problems before they become big ones.&lt;/p&gt;
&lt;h2 id=&quot;the-origins-of-your-operational-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/#the-origins-of-your-operational-data&quot;&gt;The Origins Of Your Operational Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This critical operational data doesn&#39;t live in one place; it&#39;s generated across a diverse and complex digital ecosystem.&lt;/p&gt;
&lt;p&gt;A vast amount comes directly from shop floor equipment—the PLCs that orchestrate your machines, the thousands of sensors measuring every variable, and the Historians that diligently archive past performance. Then you have your core business systems. The ERP provides the what and why through production orders, while Quality (QCS) and Maintenance (CMMS) systems add essential layers of inspection and machine health data.&lt;/p&gt;
&lt;p&gt;Each of these sources speaks its own digital language. A single factory floor is a cacophony of &lt;code&gt;Modbus&lt;/code&gt;, &lt;code&gt;OPC UA&lt;/code&gt;, &lt;code&gt;EtherNet/IP&lt;/code&gt;, and &lt;code&gt;MQTT&lt;/code&gt;, etc all running simultaneously. This mix of protocols defines the communication architecture of the operation.&lt;/p&gt;
&lt;p&gt;To better understand the data involved, its sources, and the common protocols used, let&#39;s look at a detailed breakdown:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A table showing the four main categories of data MES need&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-data-landscapes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A table showing the four main categories of data MES need&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-it&#39;s-so-difficult%2C-slow%2C-and-costly-to-access-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/#why-it&#39;s-so-difficult%2C-slow%2C-and-costly-to-access-data&quot;&gt;Why It&#39;s So Difficult, Slow, and Costly to Access Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You know what data you need and where it is. The fundamental question is: can you actually get it from your machines and deliver it to your MES?&lt;/p&gt;
&lt;p&gt;This is the central struggle where real-time decisions get delayed, opportunities are lost, and innovation is stifled. Your most valuable data is trapped. Because your factory’s systems don’t speak the same digital language, data is locked away in &amp;quot;silos,&amp;quot; inaccessible and unusable. This isn&#39;t a technical inconvenience; it&#39;s a critical business problem.&lt;/p&gt;
&lt;p&gt;Every new piece of equipment demands expensive, custom-coded integrations that are fragile and brittle. This necessitates a constant reliance on specialized programmers, driving up operational costs significantly. The result is a chaotic patchwork of inconsistent data flows, leaving you with a fragmented view of your operation instead of the unified intelligence you desperately need to make swift, informed decisions. This isn&#39;t just inefficient; it actively sabotages your agility, cripples your ability to innovate, and fundamentally undermines your competitive advantage.&lt;/p&gt;
&lt;h2 id=&quot;orchestrate-your-factory&#39;s-data-flow-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/#orchestrate-your-factory&#39;s-data-flow-with-flowfuse&quot;&gt;Orchestrate Your Factory&#39;s Data Flow with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s frustrating to know the data is there but be unable to reach it. FlowFuse was built to solve this exact problem by acting as a data acquisition layer for your factory. It creates reliable pathways for information to get from your various machines and systems directly to your MES.&lt;/p&gt;
&lt;p&gt;The power of FlowFuse lies in its foundation on the vast Node-RED ecosystem. This gives you immediate access to a library of over 5,000 pre-built connectors, or &amp;quot;nodes&amp;quot; ready to communicate with a massive array of industrial protocols. This eliminates the need for expensive, time-consuming custom code. The library includes robust nodes for standards like Modbus, OPC UA, and MQTT, as well as for specific controllers from Siemens, Mitsubishi, Omron, and more.&lt;/p&gt;
&lt;p&gt;Following are some of the most commonly used protocol nodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modbus:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-modbus&quot;&gt;https://flows.nodered.org/node/node-red-contrib-modbus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPC UA:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;https://flows.nodered.org/node/node-red-contrib-opcua&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPC DA:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opc-da&quot;&gt;https://flows.nodered.org/node/node-red-contrib-opc-da&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQTT:&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/mqtt-in/&quot;&gt;https://flowfuse.com/node-red/core-nodes/mqtt-in/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ethernet/IP:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-ethernet-ip&quot;&gt;https://flows.nodered.org/node/node-red-contrib-ethernet-ip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Siemens S7:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-s7comm&quot;&gt;https://flows.nodered.org/node/node-red-contrib-s7comm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MITSUBISHI MC:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-mcprotocol&quot;&gt;https://flows.nodered.org/node/node-red-contrib-mcprotocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OMRON FINS:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-omron-fins&quot;&gt;https://flows.nodered.org/node/node-red-contrib-omron-fins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP:&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/http-in/&quot;&gt;https://flowfuse.com/node-red/core-nodes/http-in/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LwM2M:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-lwm2m&quot;&gt;https://flows.nodered.org/node/node-red-contrib-lwm2m&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMQP:&lt;/strong&gt; &lt;a href=&quot;https://flowfuse.com/node-red/protocol/amqp/&quot;&gt;https://flowfuse.com/node-red/protocol/amqp/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serialport:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-serialport&quot;&gt;https://flows.nodered.org/node/node-red-node-serialport&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-gpio&quot;&gt;https://flows.nodered.org/node/node-red-contrib-gpio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lorawan:&lt;/strong&gt; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-lorawan&quot;&gt;https://flows.nodered.org/node/node-red-contrib-lorawan&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This extensive library allows you to reliably acquire data from various assets using a simple drag-and-drop approach, bringing your factory&#39;s siloed data into a cohesive and manageable flow.&lt;/p&gt;
&lt;p&gt;In addition to protocol connectors, there are also powerful database nodes available to integrate with systems such as InfluxDB, TimescaleDB, PostgreSQL, Microsoft SQL Server, and more—making it easy to store, query, and analyze your factory data.&lt;/p&gt;
&lt;p&gt;So, With FlowFuse, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deploy intelligent agents&lt;/strong&gt; directly to the edge, all managed from a central platform remotely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to any industrial asset&lt;/strong&gt;—PLCs, sensors, SCADA—using ready-made nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transform raw data&lt;/strong&gt; with visual logic, so it’s perfectly structured for your MES.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build custom operator dashboards&lt;/strong&gt; with pre-built UI widgets to visualize and act on data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate data flows&lt;/strong&gt; based on schedules, machine events, or production states.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure the entire process&lt;/strong&gt; with enterprise-grade features like multi-user authentication and role-based access control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scale seamlessly&lt;/strong&gt; from a single line to your entire enterprise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This isn&#39;t just about solving a technical challenge. It’s about driving business outcomes. When you can finally see your entire operation in one clear picture, your production lines run more efficiently. You&#39;ll see tangible savings as you reduce waste and catch errors before they become costly. When you are known for exceptional quality and effortless compliance, you win. You can turn the messy, trapped data that has been holding you back into the very asset that pushes you ahead of the competition.&lt;/p&gt;
&lt;h2 id=&quot;your-next-step-towards-operational-excellence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/data-acquisition-for-mes/#your-next-step-towards-operational-excellence&quot;&gt;Your Next Step Towards Operational Excellence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bridging the gap between your factory floor and your MES is a huge task. The sheer diversity of machines, systems, and protocols can seem impossible to overcome. But it doesn’t have to be a barrier to innovation.&lt;/p&gt;
&lt;p&gt;This is precisely where FlowFuse shines. It acts as the universal translator, bringing all your systems together regardless of the language they speak. With thousands of ready-to-use connectors and an intuitive low-code interface, FlowFuse empowers you to get your data flowing exactly where it needs to go.&lt;/p&gt;
&lt;p&gt;Once that live data starts moving, your MES becomes exponentially more powerful—helping you spot problems faster, plan smarter, and run your operations with confidence.&lt;/p&gt;
&lt;p&gt;Want to see it in action? &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Book a live demo&lt;/a&gt; and watch FlowFuse unlock your factory data—no custom code required.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/announcing-node-red-con-2025/</id>
        <title>Announcing Node-RED Con 2025: A Community Conference on Industrial Applications</title>
        <summary>We&#39;re excited to support this year&#39;s community conference focused on Node-RED in industry. The Call for Papers is now open!</summary>
        <updated>2025-06-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/announcing-node-red-con-2025/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;At FlowFuse, our commitment to the Node-RED community is at the heart of everything we do. That&#39;s why we are thrilled to announce our support as a sponsor for &lt;strong&gt;Node-RED Con 2025&lt;/strong&gt;, a free, online conference taking place on &lt;strong&gt;Tuesday, November 4, 2025!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This year&#39;s event is dedicated to exploring a vital theme: &lt;strong&gt;Node-RED applications in industry&lt;/strong&gt;. It’s a fantastic opportunity for developers, engineers, and innovators to connect and share how Node-RED is being used to solve real-world challenges.&lt;/p&gt;
&lt;h2 id=&quot;the-agenda-is-underway&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/announcing-node-red-con-2025/#the-agenda-is-underway&quot;&gt;The Agenda is Underway&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The conference agenda is built from community submissions, and the Call for Papers received a great response. The organizing team reports receiving many excellent submissions, so we&#39;re in for some really interesting sessions.&lt;/p&gt;
&lt;p&gt;The event will offer sessions in three different categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Full Talks &amp;amp; Demos (25-30 mins):&lt;/strong&gt; Focused on industrial use cases, IoT architectures, and edge computing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lightning Talks (8-10 mins):&lt;/strong&gt; Showcasing fun, creative, or inspiring projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expert Panelists:&lt;/strong&gt; To discuss the future of industrial automation with Node-RED.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;registration-is-now-open&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/announcing-node-red-con-2025/#registration-is-now-open&quot;&gt;Registration is Now Open&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Head to &lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;the Node-RED Con 2025 official page&lt;/a&gt; to secure your spot. Join the live event on November 4, ask your questions, be part of the conversation — this only happens once a year, and you won&#39;t want to miss what the community has built!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/optimizing-operations-improve-industrial-operations-with-flowfuse/</id>
        <title>Optimizing operations: Improve Industrial Operations with FlowFuse</title>
        <summary>FlowFuse raises $7.2M to empower you to connect the physical and digital worlds of industry.</summary>
        <updated>2025-06-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/optimizing-operations-improve-industrial-operations-with-flowfuse/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;The announcement of our latest $7.25 million funding round isn&#39;t just a milestone for FlowFuse; it&#39;s a catalyst for our mission to revolutionize how industrial data is accessed and used.&lt;/p&gt;
&lt;p&gt;Thousands of IT professionals and citizen developers now collaborate with our product on their digital transformation, and we’re expecting hundreds of thousands more to join over the next few years. We&#39;re incredibly proud of our recent growth – nearly 5x in customers and revenue just last year, a trend that’s only accelerating. But more than that, we&#39;re thrilled by what this allows us to build for you.&lt;/p&gt;
&lt;p&gt;Our focus has always been to empower engineers and operational managers to connect the physical shop floor with their digital enterprise systems. We see FlowFuse, powered by Node-RED, as that critical layer that makes data accessible, understandable, and actionable. And with this new investment, we&#39;re doubling down on making this experience even more powerful and intuitive.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-the-low-code-powerhouse-for-industrial-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/optimizing-operations-improve-industrial-operations-with-flowfuse/#flowfuse%3A-the-low-code-powerhouse-for-industrial-data&quot;&gt;FlowFuse: The Low-Code Powerhouse for Industrial Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is enabling customers to bridge the gap between their physical and digital operations. They are leveraging FlowFuse to extract the data required to implement new use-cases from a wide range of sources. FlowFuse spans both digital systems like ERPs and physical equipment on the shop floor. Using the low-code interface of Node-RED within the FlowFuse platform, this captured data is then transformed and efficiently transported to various destinations. Significantly, users are orchestrating multiple Node-RED instances through FlowFuse to collaboratively inform and automate operational decisions, even incorporating crucial operator feedback directly into the workflow.&lt;/p&gt;
&lt;p&gt;FlowFuse creates a singular and unified platform for users that not only extracts and transports data but also actively utilizes it for decision-making and incorporates human expertise, effectively closing the loop through fusing your operations with the corporate systems. The void often filled by complex SCADA systems and disparate, siloed solutions can now be seamlessly integrated and managed with FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse, the low-code powerhouse for inustrial data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/low-code-powerhouse-for-industrial-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;where-we&#39;re-going%3A-infusing-ai-for-an-even-smarter-tomorrow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/optimizing-operations-improve-industrial-operations-with-flowfuse/#where-we&#39;re-going%3A-infusing-ai-for-an-even-smarter-tomorrow&quot;&gt;Where We&#39;re Going: Infusing AI for an Even Smarter Tomorrow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the past years we’ve been focused on augmenting Node-RED to enable it to scale better for an organization. This entails many facets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure companies that are in regulated industries meet their compliance frameworks.&lt;/li&gt;
&lt;li&gt;Make it easy to run and maintain hundreds or thousands of Node-REDs.&lt;/li&gt;
&lt;li&gt;Extend DevOps to operational technology teams, ensure development is done outside of production systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our shift towards becoming an &lt;em&gt;&lt;strong&gt;end to end&lt;/strong&gt;&lt;/em&gt; platform to connect the physical world with your digital realm is next, and we’ve already started this journey. Over the past months we’ve enabled customers to store data long term by allowing them to store files on the platform. Also, we noticed that customers took longer than ideal to transport data between data consumers and producers and back again. Building a data orchestration layer, for example through a Unified Namespace (UNS), is vital to ensure data is available for building applications. So FlowFuse has allowed thousands of clients to send data through MQTT, a quick on-ramp to further the abilities for the platform of FlowFuse. Lastly, in the next FlowFuse release a data storage layer will be provided to persist and allow querying of events.&lt;/p&gt;
&lt;p&gt;While we&#39;ll continue to enhance the core capabilities users already love, a significant portion of this new investment is earmarked for integrating AI more deeply into the FlowFuse platform. The FlowFuse Expert already has proven itself countless times. However, we believe improving our AI suggestions and capabilities are the key to unlocking the next level of low-code development.&lt;/p&gt;
&lt;p&gt;While Node-RED is low-code and enables many engineers the power to integrate, automate, and interact with their operations, we want every engineer – mechanical, electrical, or operational – to harness its full potential quickly. AI will act as an intelligent guide, helping new users understand Node-RED&#39;s capabilities, learn best practices, and troubleshoot effectively. Imagine an assistant that helps you build your first flow, suggests optimal configurations, or explains complex functions in simple terms.&lt;/p&gt;
&lt;p&gt;Furthermore, we see that AI can offer suggestions, identify potential optimizations, and even help generate partial flows in Node-RED. Allowing both new and experienced users to gain momentum.
FlowFuse is on a mission to get a billion people automating, having AI make suggestions allows more people to learn how, and get started, as well as advanced users remove boilerplate to create and get to brass tacks faster.&lt;/p&gt;
&lt;h2 id=&quot;the-vision%3A-everyone-can-increase-operational-excellence&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/optimizing-operations-improve-industrial-operations-with-flowfuse/#the-vision%3A-everyone-can-increase-operational-excellence&quot;&gt;The Vision: Everyone Can Increase Operational Excellence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are millions of brilliant engineers and managers out there who understand their operations inside and out. They know what needs to be optimized, and have hunches to validate, but often lack the accessible tools to bridge the data gap. That’s what FlowFuse is for.&lt;/p&gt;
&lt;p&gt;We are committed to making it super easy to get data, derive insight, and act on that insight to optimize operations. The infusion of AI into our low-code platform is the next logical step in this journey. We&#39;re incredibly excited about the path ahead and grateful to our customers, partners, and investors for their support. The future of industrial operations is intelligent, connected, and user-empowered – and we&#39;re building it, together.&lt;/p&gt;
&lt;p&gt;Want to see how FlowFuse can help you optimize your operations? Let&#39;s talk about your specific needs and see our platform in action. &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;Schedule a demo&lt;/a&gt; with our team today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/</id>
        <title>FlowFuse Forms: Easy Data Collection for Your Factory Floor</title>
        <summary>Get Shop Floor Data Directly to Machine Settings</summary>
        <updated>2025-06-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;It&#39;s often a pain to get important data from the factory floor. Things like doing quality checks still rely on old methods like manual notes and slow spreadsheets. This can lead to delays, errors, and a lot of wasted time before anyone can actually use the information. It&#39;s especially tough when you need quick feedback from an operator.&lt;/p&gt;
&lt;p&gt;This article will show you an easy way to gather data via a form entry. We&#39;ll look at how forms in FlowFuse Dashboard can make collecting data from factory workers much simpler. You&#39;ll learn how to build useful forms that connects your team&#39;s knowledge directly to your industrial processes. As a practical example, we&#39;ll walk you through building a solution to digitize production recipe updates, showing you exactly how to implement it.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you begin, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node-RED:&lt;/strong&gt; Make sure you have an instance of Node-RED up and running. The quickest way to do this is via FlowFuse. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then you&#39;ll need to add two more sets of nodes to your palette:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Dashboard:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (also known as Node-RED Dashboard 2.0 in the community) installed and properly configured on your instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite:&lt;/strong&gt; Install the &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-sqlite&quot;&gt;node-red-node-sqlite&lt;/a&gt; package, which will be used in the practical example.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and finally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic Node-RED Knowledge:&lt;/strong&gt; You are familiar with creating and deploying basic flows in Node-RED. If not, consider taking the &lt;a href=&quot;https://node-red-academy.learnworlds.com/course/node-red-getting-started&quot;&gt;Node-RED Fundamentals Course&lt;/a&gt; &lt;em&gt;sponsored by FlowFuse.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-forms-in-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#building-forms-in-flowfuse-dashboard&quot;&gt;Building Forms in FlowFuse Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse Dashboard makes it easy to build interactive industrial applications using drag-and-drop components — &lt;strong&gt;no coding required&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;One of these components is the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-form.html&quot;&gt;Form&lt;/a&gt; widget, which allows you to create versatile forms within your applications. The Form widget supports a wide range of input types, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Text Fields&lt;/li&gt;
&lt;li&gt;Number Inputs&lt;/li&gt;
&lt;li&gt;Date Pickers,&lt;/li&gt;
&lt;li&gt;Multi-line Text Areas&lt;/li&gt;
&lt;li&gt;Dropdown Selection&lt;/li&gt;
&lt;li&gt;Checkboxes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A key benefit of this widget is that you can configure the form fields either statically (with predefined values) or dynamically (updated through your Node-RED flow), depending on your application’s needs.&lt;/p&gt;
&lt;h3 id=&quot;adding-and-configuring-the-form-widget&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#adding-and-configuring-the-form-widget&quot;&gt;Adding and Configuring the Form Widget&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Form&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the widget and create a new group for it with the correct page configuration to render it. (note: if this is the first widget you have, this will automatically be created for you)&lt;/li&gt;
&lt;li&gt;Set an appropriate size (width and height) according to your preferences.&lt;/li&gt;
&lt;li&gt;Enter the label for the form.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that we have completed all the basic and necessary configurations for the form, let’s add the input elements.&lt;/p&gt;
&lt;h3 id=&quot;adding-input-fields-to-the-form-statically&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#adding-input-fields-to-the-form-statically&quot;&gt;Adding Input Fields to the Form Statically&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding Form Elements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/adding-form-element.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding Form Elements&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The widget supports various input element types that can be tailored to specific use cases — from collecting simple text to selecting dates or choosing from predefined options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To add input elements:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+ add&lt;/strong&gt; button in the widget’s configuration dialog.&lt;/li&gt;
&lt;li&gt;A new configuration row will appear for the element.&lt;/li&gt;
&lt;li&gt;Configure each input element with the following fields:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt;: This is the visible label for the field shown to the user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: A unique key used in the message payload (e.g., &lt;code&gt;msg.payload.firstname&lt;/code&gt;) when the form is submitted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type&lt;/strong&gt;: Select the input type. Supported types include:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Text&lt;/strong&gt;: For short text inputs (e.g., name, city).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Number&lt;/strong&gt;: For numeric inputs (e.g., age, price).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Date&lt;/strong&gt;: For selecting a date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text Area&lt;/strong&gt;: For longer free-form text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dropdown&lt;/strong&gt;: For selecting from a list of predefined values.&lt;br /&gt;
&lt;em&gt;We will cover how to add options to the dropdown field in a later section.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checkbox&lt;/strong&gt;: For boolean values (checked or unchecked).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Required&lt;/strong&gt;: Check this box to make the field mandatory. The form cannot be submitted unless this field is filled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Row&lt;/strong&gt;:: If Multiline is selected, this defines the number of visible rows in the text area.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;adding-options-to-dropdown-inputs-statically&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#adding-options-to-dropdown-inputs-statically&quot;&gt;Adding Options to Dropdown Inputs Statically&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you add Dropdown type input element to the Form widget, you need to provide a list of &lt;code&gt;options&lt;/code&gt; that the user can choose from. These options can be configured in the widget&#39;s configuration dialog.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the widget&#39;s configuration dialog, switch to the &amp;quot;Dropdown Options&amp;quot; tab.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+ add&lt;/strong&gt; button to insert a new option row.&lt;/li&gt;
&lt;li&gt;In the new row, fill in the following fields:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dropdown&lt;/strong&gt;: Select the dropdown input field you want to add options to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Value&lt;/strong&gt;: The internal value that will be sent in the form payload when this option is selected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt;: The visible text shown to the user in the dropdown list.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Repeat this process for each option you want to add.&lt;/p&gt;
&lt;h3 id=&quot;pre-filling-forms-with-default-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#pre-filling-forms-with-default-values&quot;&gt;Pre-filling Forms with Default Values&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can pre-fill forms with default values to streamline user input, reduce typing errors, and save time. This is especially useful in scenarios like editing an existing recipe, where the current details can be loaded directly into the form.&lt;/p&gt;
&lt;p&gt;We can pass data to the &lt;code&gt;ui-form&lt;/code&gt; node in our flow to set these values dynamically. To do this, send an object in &lt;code&gt;msg.payload&lt;/code&gt; to the input of the relevant node. Each key of &lt;code&gt;msg.payload&lt;/code&gt; corresponds to a form field and its value represents the pre-filled data.&lt;/p&gt;
&lt;p&gt;For example, if your form includes fields for &lt;code&gt;product_name&lt;/code&gt; and &lt;code&gt;target_temperature_c&lt;/code&gt;, you can send a &lt;code&gt;msg.payload&lt;/code&gt; like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-259&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-259&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;product_name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Eco-Friendly Coating&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;target_temperature_c&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;120.0&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-259&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;add-form-input-elements-dynamically-at-runtime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#add-form-input-elements-dynamically-at-runtime&quot;&gt;Add Form Input Elements Dynamically at Runtime&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In some cases, you may need to define form elements dynamically based on real-time data.&lt;/p&gt;
&lt;p&gt;For example, you might want to show additional fields based on a user’s selection or load dropdown options from an external API. This dynamic capability adds a new level of flexibility and interactivity to your forms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To define form fields at runtime:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the &lt;code&gt;msg.ui_update.options&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt; should contain an array of objects, where each object defines the new configuration for the element:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below are the supported element types and their corresponding JSON configurations:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Element Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;JSON Configuration&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;text&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;name&amp;quot;, &amp;quot;required&amp;quot;: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multiline&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;multiline&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Name&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;name&amp;quot;, &amp;quot;required&amp;quot;: true, &amp;quot;rows&amp;quot;: 4 } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Password&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;password&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Password&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;password&amp;quot;, &amp;quot;required&amp;quot;: true } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Email&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;email&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;E-Mail Address&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;email&amp;quot;, &amp;quot;required&amp;quot;: true } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Number&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Age&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;age&amp;quot;, &amp;quot;required&amp;quot;: true }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Checkbox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;checkbox&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Subscribe to Newsletter&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;newsletter&amp;quot; } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Switch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;switch&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Enable Notifications&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;notifications&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;date&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Date of Birth&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;dob&amp;quot;, &amp;quot;required&amp;quot;: true } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;time&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Time of Birth&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;tob&amp;quot;, &amp;quot;required&amp;quot;: true } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dropdown&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;dropdown&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;Dropdown&amp;quot;, &amp;quot;key&amp;quot;: &amp;quot;selection&amp;quot; } &lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;adding-options-to-dropdown-inputs-dynamically-at-runtime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#adding-options-to-dropdown-inputs-dynamically-at-runtime&quot;&gt;Adding Options to Dropdown Inputs Dynamically at Runtime&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To update the options of a dropdown field at runtime, use the &lt;code&gt;msg.ui_update.dropdownOptions&lt;/code&gt; property in your flow.&lt;/p&gt;
&lt;p&gt;This is useful when you want to update just the dropdown options without changing the rest of the form.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-393&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-393&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;dropdown&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Machine Type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Option A&quot;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;dropdown&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Machine Type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Option B&quot;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-393&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The &amp;quot;dropdown&amp;quot; refers to the name of the dropdown field you want to add options for. The &amp;quot;value&amp;quot; represents the internal value that is sent when the user selects the option. The &amp;quot;label&amp;quot; is the option displayed to the user in the dropdown.&lt;/p&gt;
&lt;h2 id=&quot;handling-input-data-collected-from-the-dashboard-form&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#handling-input-data-collected-from-the-dashboard-form&quot;&gt;Handling Input Data Collected from the Dashboard Form&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a user submits the dashboard form, the input data is sent to Node-RED, where it can be accessed and processed. This enables you to perform tasks such as validating the data, transforming it, or sending it to other systems like databases or APIs.&lt;/p&gt;
&lt;h3 id=&quot;retrieving-submitted-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#retrieving-submitted-data&quot;&gt;Retrieving Submitted Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The data submitted from the form is transmitted to any nodes connected to the output of the &lt;code&gt;ui-from&lt;/code&gt; node, and is contained within &lt;code&gt;msg.payload&lt;/code&gt;. Each field’s value can be accessed using the field’s key or name as the property within &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, let’s say the form includes the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Device Name (key: &lt;code&gt;device_name&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Device ID (key: &lt;code&gt;device_id&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Device Serial Number (key: &lt;code&gt;serial_number&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Country (key: &lt;code&gt;country&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After submission, you can access these values like this in your flow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Device Name: &lt;code&gt;msg.payload.device_name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Device ID: &lt;code&gt;msg.payload.device_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Device Serial Number: &lt;code&gt;msg.payload.serial_number&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Country: &lt;code&gt;msg.payload.country&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use this data anywhere in your flow — for example, to save it in a database or store it in &lt;a href=&quot;https://flowfuse.com/docs/user/persistent-context/#flowfuse-persistent-context&quot;&gt;FlowFuse’s context storage&lt;/a&gt;. Crucially, this collected data can also directly instruct machines on the shop floor, with FlowFuse Device Agent managing that precise control.&lt;/p&gt;
&lt;h2 id=&quot;building-your-dynamic-production-recipe-update-form&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#building-your-dynamic-production-recipe-update-form&quot;&gt;Building Your Dynamic Production Recipe Update Form&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, you will build an advanced flow for dynamically updating production recipes using FlowFuse Forms.&lt;/p&gt;
&lt;p&gt;A production recipe, often referred to as a manufacturing recipe or master batch record, is a critical set of instructions that defines the precise parameters, ingredients, and steps required to produce a specific product consistently. This includes details like material quantities, temperature, mixing speeds, pressures, and hold times.&lt;/p&gt;
&lt;p&gt;This setup uses a &lt;strong&gt;ui-dropdown&lt;/strong&gt; for selecting recipes and a &lt;strong&gt;ui-form&lt;/strong&gt; that dynamically populates and allows updates to recipe parameters. Everything you have learned so far will come together here to create a practical and interactive solution.&lt;/p&gt;
&lt;h3 id=&quot;set-up-your-sqlite-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#set-up-your-sqlite-database&quot;&gt;Set Up Your SQLite Database&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the following flow to quickly set up your SQLite database. It creates a recipes table and populates it with demo data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Import the flow into your Node-RED editor (from the example provided below).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow to activate it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the Inject node labeled &amp;quot;Populate Demo Recipes&amp;quot; to insert the sample data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-223&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow223 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;b9693cc84311ae8e&#92;&quot;,&#92;&quot;e7619cfe7c7fdaa9&#92;&quot;,&#92;&quot;f9e35c9c3b213d47&#92;&quot;,&#92;&quot;c719f2b43aef7d44&#92;&quot;,&#92;&quot;69a914bb0479925c&#92;&quot;,&#92;&quot;bb3da75dcf2b4cdd&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:79,&#92;&quot;w&#92;&quot;:752,&#92;&quot;h&#92;&quot;:162},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9693cc84311ae8e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS recipes (&#92;&#92;n    recipe_id TEXT PRIMARY KEY NOT NULL,          -- Unique internal identifier (e.g., &#39;PX-BLEND-V3&#39;)&#92;&#92;n    product_name TEXT NOT NULL,                   -- Human-readable product name (e.g., &#39;Premium Polymer Blend&#39;)&#92;&#92;n    version_no TEXT NOT NULL,                     -- Recipe version (e.g., &#39;3.1&#39;, &#39;A-Rev&#39;)&#92;&#92;n    target_temperature_c REAL NOT NULL,           -- Target temperature in Celsius&#92;&#92;n    mixing_speed_rpm INTEGER NOT NULL,            -- Mixing speed in Revolutions Per Minute&#92;&#92;n    pressure_bar REAL,                            -- Pressure in Bar (more common than PSI in many regions)&#92;&#92;n    material_a_kg REAL NOT NULL,                  -- Quantity of main material A in kilograms&#92;&#92;n    material_b_kg REAL,                           -- Quantity of secondary material B in kilograms (optional for some recipes)&#92;&#92;n    catalyst_ml REAL,                             -- Quantity of catalyst in milliliters (specific additive)&#92;&#92;n    hold_time_min INTEGER NOT NULL,               -- Hold time in minutes at target temperature&#92;&#92;n    description TEXT,                             -- Optional notes about the recipe&#92;&#92;n    created_date TEXT NOT NULL                    -- Date recipe was created/last updated (ISO format)&#92;&#92;n);&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f9e35c9c3b213d47&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7619cfe7c7fdaa9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Recipe table&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b9693cc84311ae8e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f9e35c9c3b213d47&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c719f2b43aef7d44&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;INSERT INTO recipes (recipe_id, product_name, version_no, target_temperature_c, mixing_speed_rpm, pressure_bar, material_a_kg, material_b_kg, catalyst_ml, hold_time_min, description, created_date)&#92;&#92;nVALUES&#92;&#92;n(&#39;POLY_BLEND_V3.1&#39;, &#39;Advanced Polymer Resin&#39;, &#39;3.1&#39;, 195.0, 850, 1.5, 1250.0, 450.0, 15.0, 60, &#39;Improved tensile strength for injection molding. Requires high shear.&#39;, &#39;2025-01-10&#39;),&#92;&#92;n(&#39;COATING_ECO_V1.2&#39;, &#39;Eco-Shield Protective Coating&#39;, &#39;1.2&#39;, 110.0, 320, 0.8, 800.0, 200.0, 5.0, 30, &#39;Low VOC formulation, quick dry time. Mix gently.&#39;, &#39;2024-11-22&#39;),&#92;&#92;n(&#39;ADHESIVE_FAST_CURE&#39;, &#39;Industrial Adhesive X-500&#39;, &#39;1.0&#39;, 70.0, 550, 2.1, 300.0, 120.0, 10.0, 15, &#39;Fast-curing formulation for rapid assembly. Must maintain precise temperature.&#39;, &#39;2025-03-01&#39;),&#92;&#92;n(&#39;FOOD_LIQUID_PURE&#39;, &#39;PureBev Beverage Base&#39;, &#39;2.0&#39;, 85.0, 180, 0.5, 2000.0, 500.0, NULL, 45, &#39;Food-grade liquid base. Ensure sterile conditions. No catalyst used.&#39;, &#39;2025-02-15&#39;),&#92;&#92;n(&#39;PHARMA_API_MIX&#39;, &#39;API Compound Blend Alpha&#39;, &#39;1.0&#39;, 45.0, 400, 1.2, 50.0, 25.0, 2.0, 90, &#39;Active Pharmaceutical Ingredient blend. Temperature sensitive. Strict hold time.&#39;, &#39;2025-04-05&#39;);&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bb3da75dcf2b4cdd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;69a914bb0479925c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Populate Demo Recipes&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c719f2b43aef7d44&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bb3da75dcf2b4cdd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d248b8387940a5bc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlitedb&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;/tmp/sqlite&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;RWC&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow223.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-223&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;initial-setup%3A-populate-dropdown-and-define-form-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#initial-setup%3A-populate-dropdown-and-define-form-structure&quot;&gt;Initial Setup: Populate Dropdown and Define Form Structure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We want this flow to run when our dashboard page loads. It queries your exiting recipes and then dynamically defines both the &lt;strong&gt;ui-dropdown&#39;s&lt;/strong&gt; options and the &lt;strong&gt;ui-form&#39;s&lt;/strong&gt; structure.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an Event node onto the canvas. This node send a message when the dashboard page loads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;ui-event&lt;/strong&gt; node to an &lt;strong&gt;sqlite&lt;/strong&gt; node. Configure it to connect to your SQLite database, set SQL Query to fixed, and enter &lt;code&gt;SELECT recipe_id FROM recipes;&lt;/code&gt; as the query. Ensure Return Output is set to a &amp;quot;Parsed JSON Object&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;sqlite&lt;/strong&gt; node&#39;s output to a new &lt;strong&gt;function&lt;/strong&gt; node. Name it &amp;quot;Generate Form &amp;amp; Dropdown Definition&amp;quot;. In this function, you will write JavaScript to dynamically create the form&#39;s elements and populate the dropdown options. Set the function to have 2 outputs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-524&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-524&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// msg.payload contains the recipe_id and recipe_name from SQLite query.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dropdownOptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    dropdownOptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recipe_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// Internal value for dropdown&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recipe_name       &lt;span class=&quot;token comment&quot;&gt;// Display text for dropdown&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// --- Define the ui_form structure (all input elements) ---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; formElements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Recipe ID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;recipe_id_display&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;readOnly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product Name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;product_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;readOnly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Version No.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;version_no&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;readOnly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Target Temp (°C)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;target_temperature_c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mixing Speed (RPM)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mixing_speed_rpm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pressure (Bar)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pressure_bar&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Material A (kg)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;material_a_kg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Material B (kg)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;material_b_kg&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Catalyst (ml)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;catalyst_ml&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hold Time (min)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hold_time_min&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;multiline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;readOnly&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;rows&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Output 1: For the ui_dropdown node (msg.options)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; msg1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; dropdownOptions &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Output 2: For the ui_form node (msg.ui_update.options)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; msg2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ui_update&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; formElements &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;msg1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg2&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Send two separate messages&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-524&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui-dropdown&lt;/strong&gt; node onto the canvas. Configure its dashboard group and label (Select Recipe ID:). Ensure its &amp;quot;Options&amp;quot; list is empty, as it will be populated dynamically. Connect the first output of the &amp;quot;Generate Form &amp;amp; Dropdown Definition&amp;quot; &lt;strong&gt;function&lt;/strong&gt; to the input of this &lt;strong&gt;ui_dropdown&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui-form&lt;/strong&gt; widget onto the canvas. Configure its dashboard group and label (Recipe Parameters). Crucially, leave its &amp;quot;Options&amp;quot; list completely empty in its properties. Set the &amp;quot;Submit&amp;quot; button text to Apply and &amp;quot;Cancel&amp;quot; to Clear.  Connect the second output of the &amp;quot;Generate Form &amp;amp; Dropdown Definition&amp;quot; &lt;strong&gt;function&lt;/strong&gt; to the input of this &lt;strong&gt;ui-form&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy your flow and open the dashboard. You should now see your form with the &amp;quot;Select Recipe&amp;quot; dropdown populated.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;populate-form-on-recipe-selection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#populate-form-on-recipe-selection&quot;&gt;Populate Form on Recipe Selection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This flow segment pre-fills the form with recipe details when an operator selects a recipe from the dropdown.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of your dropdown node (from Step 2). This output will carry the selected &lt;code&gt;recipe_id&lt;/code&gt; in &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;ui-dropdown&lt;/strong&gt; output to a &lt;strong&gt;change&lt;/strong&gt; node. Name it Set Params &amp;amp; Flow Context. Set &lt;code&gt;msg.params.$recipe_id&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt; and &lt;code&gt;flow.selected_recipe_id&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;change&lt;/strong&gt; node to an &lt;strong&gt;sqlite&lt;/strong&gt; node. Configure it for your database, set SQL Query to prepared statement, and enter &lt;code&gt;SELECT * FROM recipes WHERE recipe_id = $recipe_id;&lt;/code&gt; as the prepared statement. Ensure you add a rule in change node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;msg.params.$recipe_id&lt;/code&gt; to &lt;code&gt;msg.payload.recipe_id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;sqlite&lt;/strong&gt; node&#39;s output to a &lt;strong&gt;function&lt;/strong&gt; node. Name it Show values to form fields. This function will format the retrieved recipe details to pre-fill the form.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-577&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-577&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; recipeDetails &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Get the first (and only) result&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Map recipe details to the keys of your form elements for pre-filling.&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;recipe_id_display&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recipe_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// For the display field in ui_form&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;product_name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;version_no&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;version_no&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;target_temperature_c&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_temperature_c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;mixing_speed_rpm&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mixing_speed_rpm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;pressure_bar&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pressure_bar&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;material_a_kg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;material_a_kg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;material_b_kg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;material_b_kg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;catalyst_ml&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;catalyst_ml&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;hold_time_min&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hold_time_min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipeDetails&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// If selection is cleared, prepare an empty payload (except for selected_recipe_id)&lt;/span&gt;&lt;br /&gt;    msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-577&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Connect the output of the Show values to form fields &lt;strong&gt;function&lt;/strong&gt; node back to the input of your form widget (from Step 2).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;handle-form-submission-%26-update-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#handle-form-submission-%26-update-database&quot;&gt;Handle Form Submission &amp;amp; Update Database&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This flow segment processes the data when the operator clicks the &amp;quot;Apply&amp;quot; button, updating the recipe in your database and providing feedback.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect a new wire from the main output of your &lt;strong&gt;ui-form&lt;/strong&gt; widget. This output fires when the form is submitted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the form&#39;s output to a &lt;strong&gt;change&lt;/strong&gt; node. Name it Prepare Update Params. This node will prepare the &lt;code&gt;msg.params&lt;/code&gt; object for the SQLite update.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Rules:
&lt;ul&gt;
&lt;li&gt;set &lt;code&gt;msg.params&lt;/code&gt; to JSON &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;set &lt;code&gt;msg.params.$recipe_id&lt;/code&gt; to &lt;code&gt;flow.selected_recipe_id&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each editable field in your form (e.g., target_temperature_c, mixing_speed_rpm), add a rule: set &lt;code&gt;msg.params.$[FIELD_NAME] to msg.payload.[FIELD_NAME]&lt;/code&gt;.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;change&lt;/strong&gt; node to an &lt;strong&gt;sqlite&lt;/strong&gt; node.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure it for your database, set SQL Query to prepared statement.&lt;/li&gt;
&lt;li&gt;Paste your UPDATE SQL query into the &amp;quot;Prepared Statement&amp;quot; field, using the $parameters that match your msg.params.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;sqlite&lt;/strong&gt; node&#39;s output to a &lt;strong&gt;switch&lt;/strong&gt; node. Name it Check for Update Success.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set Property to payload and Rules to is empty.&lt;/li&gt;
&lt;li&gt;Add 1 output.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;switch&lt;/strong&gt; node&#39;s output to a &lt;strong&gt;change&lt;/strong&gt; node. Name it Success Message.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to str &amp;quot;Recipe updated successfully&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;change&lt;/strong&gt; node to a &lt;strong&gt;ui-notification&lt;/strong&gt; node to display the success message on the dashboard.&lt;/li&gt;
&lt;li&gt;Deploy the flow, open the dashboard, and try selecting different recipes and updating them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For practice, we use an SQLite database. However, since your recipe is often used across an entire production line, it is recommended to store it in a dedicated database instead of locally in SQLite. This ensures it is accessible to all systems and can be utilized by other components in the workflow.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This is just a simple demo we built. When using it in a production environment, you might need to make additional considerations based on your specific requirements.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse form designed for updating production recipes. The form shows a dropdown for recipe selection, dynamically populates fields with recipe parameters, and allows the user to modify and submit updates.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/recipe-update-form.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A demonstration of the dynamic &lt;strong&gt;form for recipe updates&lt;/strong&gt; in action, showing how it streamlines data entry and submission.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is the complete flow of the system we built.&lt;/p&gt;
&lt;div id=&quot;nr-flow-224&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow224 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a6eb2848159c68f4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-form&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Form&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;83b5766434e42005&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;demo&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;demo&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:false,&#92;&quot;rows&#92;&quot;:null}],&#92;&quot;formValue&#92;&quot;:{&#92;&quot;demo&#92;&quot;:&#92;&quot;&#92;&quot;},&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;submit&#92;&quot;:&#92;&quot;Apply&#92;&quot;,&#92;&quot;cancel&#92;&quot;:&#92;&quot;Clear&#92;&quot;,&#92;&quot;resetOnSubmit&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;splitLayout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;dropdownOptions&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1170,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;26303a8d6785dc68&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5b2f1f1e42391625&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Generate Form &amp;amp; Dropdown Definition&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// msg.payload contains the recipe_id and recipe_name from SQLite query.&#92;&#92;nlet dropdownOptions = [];&#92;&#92;nif (msg.payload &amp;amp;&amp;amp; Array.isArray(msg.payload)) {&#92;&#92;n    dropdownOptions = msg.payload.map(recipe =&amp;gt; {&#92;&#92;n        return {&#92;&#92;n            value: recipe.recipe_id,        // Internal value for dropdown&#92;&#92;n            label: recipe.recipe_name       // Display text for dropdown&#92;&#92;n        };&#92;&#92;n    });&#92;&#92;n}&#92;&#92;n&#92;&#92;n// --- Define the ui_form structure (all input elements) ---&#92;&#92;nlet formElements = [&#92;&#92;n    { type: &#92;&#92;&#92;&quot;text&#92;&#92;&#92;&quot;, label: &#92;&#92;&#92;&quot;Product Name&#92;&#92;&#92;&quot;, key: &#92;&#92;&#92;&quot;product_name&#92;&#92;&#92;&quot;, readOnly: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;text&#92;&#92;&#92;&quot;, label: &#92;&#92;&#92;&quot;Version No.&#92;&#92;&#92;&quot;, key: &#92;&#92;&#92;&quot;version_no&#92;&#92;&#92;&quot;, readOnly: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, label: &#92;&#92;&#92;&quot;Target Temp (°C)&#92;&#92;&#92;&quot;, key: &#92;&#92;&#92;&quot;target_temperature_c&#92;&#92;&#92;&quot;, required: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, label: &#92;&#92;&#92;&quot;Mixing Speed (RPM)&#92;&#92;&#92;&quot;, key: &#92;&#92;&#92;&quot;mixing_speed_rpm&#92;&#92;&#92;&quot;, required: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, label: &#92;&#92;&#92;&quot;Pressure (Bar)&#92;&#92;&#92;&quot;, key: &#92;&#92;&#92;&quot;pressure_bar&#92;&#92;&#92;&quot; },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Material A (kg)&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;key&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;material_a_kg&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;required&#92;&#92;&#92;&quot;: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Material B (kg)&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;key&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;material_b_kg&#92;&#92;&#92;&quot; },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Catalyst (ml)&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;key&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;catalyst_ml&#92;&#92;&#92;&quot; },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;number&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Hold Time (min)&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;key&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;hold_time_min&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;required&#92;&#92;&#92;&quot;: true },&#92;&#92;n    { type: &#92;&#92;&#92;&quot;multiline&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;label&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Description&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;key&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;description&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;readOnly&#92;&#92;&#92;&quot;: true, &#92;&#92;&#92;&quot;rows&#92;&#92;&#92;&quot;: 3 }&#92;&#92;n];&#92;&#92;n&#92;&#92;n// Output 1: For the ui_dropdown node (msg.options)&#92;&#92;nlet msg1 = { options: dropdownOptions };&#92;&#92;n&#92;&#92;n// Output 2: For the ui_form node (msg.ui_update.options)&#92;&#92;nlet msg2 = { ui_update: { options: formElements } };&#92;&#92;n&#92;&#92;nreturn [msg1, msg2]; // Send two separate messages&#92;&quot;,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;80a5a9f40e19f5a7&#92;&quot;],[&#92;&quot;a6eb2848159c68f4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9038572da428216c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;prepared&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;SELECT * FROM recipes WHERE recipe_id = $recipe_id;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1610,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;462db842ba535af6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c2536d7e7a260bc1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$recipe_id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;selected_recipe_id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1420,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9038572da428216c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;462db842ba535af6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Show values to form fields&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// msg.payload will be an array with one object: [{ recipe_id: &#39;...&#39;, recipe_name: &#39;...&#39;, ... }]&#92;&#92;nlet recipeDetails = msg.payload[0]; // Get the first (and only) result&#92;&#92;n&#92;&#92;nif (recipeDetails) {&#92;&#92;n    // Map recipe details directly to the keys of your form elements&#92;&#92;n    // This msg.payload will be sent to the ui_form to pre-fill its fields&#92;&#92;n    msg.payload = {&#92;&#92;n        selected_recipe_id: recipeDetails.recipe_id, // Keep the dropdown selected&#92;&#92;n        product_name: recipeDetails.product_name,&#92;&#92;n        version_no: recipeDetails.version_no,&#92;&#92;n        target_temperature_c: recipeDetails.target_temperature_c,&#92;&#92;n        mixing_speed_rpm: recipeDetails.mixing_speed_rpm,&#92;&#92;n        pressure_bar: recipeDetails.pressure_bar,&#92;&#92;n        material_a_kg: recipeDetails.material_a_kg,&#92;&#92;n        material_b_kg: recipeDetails.material_b_kg,&#92;&#92;n        catalyst_ml: recipeDetails.catalyst_ml,&#92;&#92;n        hold_time_min: recipeDetails.hold_time_min,&#92;&#92;n        description: recipeDetails.description&#92;&#92;n    };&#92;&#92;n} else {&#92;&#92;n    // Clear non-dropdown fields if no recipe found (e.g., if dropdown cleared)&#92;&#92;n    let currentSelection = msg.payload.selected_recipe_id;&#92;&#92;n    msg.payload = { selected_recipe_id: currentSelection }; // Keep dropdown value but clear others&#92;&#92;n}&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1840,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9ff423aae018ab04&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e495f9bc79062be3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;SELECT recipe_id FROM recipes;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5b2f1f1e42391625&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9d6013fa166356cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;ee052dbdb58cf632&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e495f9bc79062be3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;80a5a9f40e19f5a7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-dropdown&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;83b5766434e42005&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dropdown&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Select Recipe ID:&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;multiple&#92;&quot;:false,&#92;&quot;chips&#92;&quot;:false,&#92;&quot;clearable&#92;&quot;:false,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;typeIsComboBox&#92;&quot;:true,&#92;&quot;msgTrigger&#92;&quot;:&#92;&quot;onChange&#92;&quot;,&#92;&quot;x&#92;&quot;:1190,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c2536d7e7a260bc1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9ff423aae018ab04&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;a4c1676c7c656ff3&#92;&quot;],&#92;&quot;x&#92;&quot;:2025,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a4c1676c7c656ff3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 1&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;9ff423aae018ab04&#92;&quot;],&#92;&quot;x&#92;&quot;:905,&#92;&quot;y&#92;&quot;:820,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a6eb2848159c68f4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;26303a8d6785dc68&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$recipe_id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;selected_recipe_id&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;flow&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$product_name&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.product_name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$version_no&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.version_no&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$target_temperature_c&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.target_temperature_c&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$mixing_speed_rpm&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.mixing_speed_rpm&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$pressure_bar&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.pressure_bar&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$material_a_kg&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.material_a_kg&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$material_b_kg&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.material_b_kg&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$catalyst_ml&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.catalyst_ml&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$hold_time_min&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.hold_time_min&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$description&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.description&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1420,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;656fb4832e9224b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;656fb4832e9224b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;prepared&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;-- Update key parameters for a specific recipe&#92;&#92;nUPDATE recipes&#92;&#92;nSET &#92;&#92;n    target_temperature_c = $target_temperature_c,&#92;&#92;n    mixing_speed_rpm = $mixing_speed_rpm,&#92;&#92;n    pressure_bar = $pressure_bar,&#92;&#92;n    material_a_kg = $material_a_kg,&#92;&#92;n    material_b_kg = $material_b_kg,&#92;&#92;n    catalyst_ml = $catalyst_ml,&#92;&#92;n    hold_time_min = $hold_time_min,&#92;&#92;n    description = $description,&#92;&#92;n    version_no = $version_no&#92;&#92;nWHERE recipe_id = $recipe_id&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1610,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e82526d367b028b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;81a84dcab301a18f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;ee052dbdb58cf632&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;allowConfirm&#92;&quot;:false,&#92;&quot;confirmText&#92;&quot;:&#92;&quot;Confirm&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:2110,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e82526d367b028b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;empty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1770,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;20e94224438447c1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;20e94224438447c1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Recipe updated successfully.&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1920,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;81a84dcab301a18f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;83b5766434e42005&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Recipe Form&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;a9aa17e3cfcd76d0&#92;&quot;,&#92;&quot;width&#92;&quot;:6,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5e345bf74f08f47c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlitedb&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;/tmp/sqlite&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;RWC&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ee052dbdb58cf632&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true,&#92;&quot;allowInstall&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;a9aa17e3cfcd76d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Recipe&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;ee052dbdb58cf632&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/recipe&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;326855cf654199bc&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;326855cf654199bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#222322&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#222322&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow224.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-224&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-forms-easy-data-collection-factory-floor/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, getting your factory data digital doesn&#39;t have to be a headache. Relying on paper or tricky old systems just causes slowdowns and mistakes. Plus, many digital form tools are too complicated or don&#39;t play nice with your current setup.&lt;/p&gt;
&lt;p&gt;That&#39;s where FlowFuse comes in. It lets your engineers build exactly what they need for the factory, using simple drag-and-drop tools – no coding required. This means you can ditch the manual steps, cut down on errors, save time, and even lower your IT costs.&lt;/p&gt;
&lt;p&gt;Also wiith FlowFuse, you get accurate, real-time data and better control, helping your factory run smarter and much more efficiently.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to see how FlowFuse can reduce costs, boost profits, and increase production? &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Get in touch with us.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/what-is-mes/</id>
        <title>What Is MES (Manufacturing Execution System)? How It Works, Benefits, and Challenges</title>
        <summary>MES Explained: Essential Insights for Factory Operations</summary>
        <updated>2025-06-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/what-is-mes/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Running a factory means constantly pushing for better production. You want to make more products, make them faster, and ensure they&#39;re all high quality. But often, the challenge is simply knowing what&#39;s actually happening on the factory floor, right now. Is a machine broken? Are we on track with our orders? Is the quality holding up? Getting these answers often involves manual checks, waiting for reports, or just guessing.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://flowfuse.com/solutions/mes/&quot;&gt;Manufacturing Execution System (MES)&lt;/a&gt; solves this. It&#39;s the central system that connects your factory&#39;s production to its plans. It gives you clear, instant visibility and control over every step on your shop floor.&lt;/p&gt;
&lt;p&gt;Whether you&#39;ve managed factory operations for years or are just starting to understand how they work, the need for this kind of clarity is universal.&lt;/p&gt;
&lt;p&gt;In this article, our goal is to make sure you clearly understand exactly what an MES is and, just as importantly, what it isn&#39;t. We&#39;ll explore why it&#39;s a critical tool for any modern factory that wants to produce better, faster, and with fewer problems, and we&#39;ll look at its major components.&lt;/p&gt;
&lt;h2 id=&quot;what-is-mes%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#what-is-mes%3F&quot;&gt;What is MES?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Manufacturing Execution System (MES) is the operational backbone of a modern factory. It&#39;s not merely a software program, but a dynamic, integrated system designed to bridge the crucial gap between your enterprise-level business planning and the real-time execution of production on the shop floor.&lt;/p&gt;
&lt;p&gt;Think of MES as the intelligent conductor of your manufacturing orchestra. It orchestrates all the elements of production – machines, materials, people, and processes – in real-time, ensuring that your strategic plans translate into tangible products efficiently and effectively.&lt;/p&gt;
&lt;p&gt;The MES collects real-time information to tell you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What products are currently being built.&lt;/li&gt;
&lt;li&gt;How many of them are finished.&lt;/li&gt;
&lt;li&gt;Which machines are working, and if any are having issues.&lt;/li&gt;
&lt;li&gt;What materials are being used up.&lt;/li&gt;
&lt;li&gt;If the quality of the products is good, right as they&#39;re being made.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means you always know the exact status of your production, live. Such real-time insights and operational control are at the core of what a modern MES delivers, often leveraging flexible platforms like FlowFuse to connect diverse factory data and orchestrate workflows.&lt;/p&gt;
&lt;h2 id=&quot;what-mes-is-not&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#what-mes-is-not&quot;&gt;What MES is NOT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s easy to get confused about all the different computer systems in a factory. To really get what a MES does, it helps to know what it isn&#39;t.&lt;/p&gt;
&lt;p&gt;Many people think an MES is the same as their ERP system. But that&#39;s not quite right. Your ERP (Enterprise Resource Planning) handles the big company plans like money, sales orders, and buying materials for the long run. An MES doesn&#39;t do this planning. Its job is focused purely on the factory floor, managing what&#39;s happening right now to build products. It makes sure the production plans actually get done.&lt;/p&gt;
&lt;p&gt;Another common confusion is that an MES is like a &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;SCADA&lt;/a&gt; or PLC system. Again, this isn&#39;t accurate. SCADA (Supervisory Control and Data Acquisition) and &lt;a href=&quot;https://flowfuse.com/blog/2025/12/what-is-plc/&quot;&gt;PLC&lt;/a&gt; (Programmable Logic Controller) systems are connected directly to individual machines. They tell machines what to do—like turning them on or off—and collect basic data from them. An MES doesn&#39;t control machines directly. Instead, the MES acts like the main manager for the whole factory&#39;s production. It gathers information from those machine controllers (SCADA/PLCs) and uses it to oversee the entire process, including guiding workers, checking quality, and making sure all the machines work together to finish an order.&lt;/p&gt;
&lt;p&gt;So, while ERP plans the business, and SCADA/PLC run the machines, the MES is the crucial system that manages the actual production process that happens in between.&lt;/p&gt;
&lt;h2 id=&quot;where-does-mes-sit-in-your-factory%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#where-does-mes-sit-in-your-factory%3F&quot;&gt;Where Does MES Sit in Your Factory?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To truly get the clear view and control you need over your factory&#39;s operations, it helps to understand exactly where a MES fits. Your factory&#39;s computer systems are often set up in different layers, a common way to organize them is by following the ISA-95 standard.&lt;/p&gt;
&lt;p&gt;Your MES sits right in the crucial middle layer. It acts as the key link between the big plans made higher up and the actual machines doing the work.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MES System in the isa-95 layers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/SA-95-hierarchical-view-of-automation-infrastructures.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[MES System in the isa-95 layers]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At the very top, you have your main planning system, usually an ERP. The MES takes the plans from this ERP. Its job is to ensure they are carried out perfectly on the factory floor, moment by moment, guiding and watching every single step of making your products. Below the MES are systems like SCADA. The MES tells these systems what to do with the machines, and they send live information back, giving you an instant picture of production.&lt;/p&gt;
&lt;p&gt;So, the MES is the central connection. It joins your company&#39;s big plans with the exact, real-time work on the factory floor&lt;/p&gt;
&lt;h2 id=&quot;why-your-factory-needs-mes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#why-your-factory-needs-mes&quot;&gt;Why Your Factory Needs MES&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your factory needs to do more than just make products. It needs to stay ahead of rivals, innovate, and boost profits. An MES helps your factory achieve these important goals.&lt;/p&gt;
&lt;p&gt;Here&#39;s why an MES is vital for your factory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You&#39;ll always be ready:&lt;/strong&gt; Instead of just fixing problems, you&#39;ll see them coming. This helps you make things better and react quickly to changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top quality, every time:&lt;/strong&gt; An MES helps you check and control quality at each step. This means fewer mistakes, and customers will trust your brand more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make the most of everything:&lt;/strong&gt; You&#39;ll use your machines, materials, and people better. This cuts down on waste and makes sure every part of your factory works at its best.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier to innovate:&lt;/strong&gt; With good data and clear processes, you can try new ideas and bring better products to market faster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increased profits:&lt;/strong&gt; By making things more efficiently, cutting errors, and delivering on time, an MES directly helps your factory earn more money and grow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An MES isn&#39;t just another system. It&#39;s a key tool that helps your factory become smarter, more responsive, and more profitable.&lt;/p&gt;
&lt;h2 id=&quot;essential-modules-of-mes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#essential-modules-of-mes&quot;&gt;Essential Modules of MES&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned earlier, MES isn&#39;t just one big piece of software; it&#39;s made up of several important parts that work together to manage your factory floor.&lt;/p&gt;
&lt;p&gt;One key part helps with &lt;strong&gt;scheduling and dispatching production&lt;/strong&gt; – it decides what specific jobs need to be done, when, and on which machines. Another important piece is for &lt;strong&gt;managing all your resources&lt;/strong&gt;, meaning it keeps track of your equipment, tools, and even your people, making sure everything is available when needed.&lt;/p&gt;
&lt;p&gt;Then there&#39;s the part that handles &lt;strong&gt;data collection&lt;/strong&gt;, gathering all the live information directly from machines and sensors on the floor. This ties into &lt;strong&gt;quality management&lt;/strong&gt;, which makes sure products meet standards at every step by guiding checks and recording results. An MES also includes &lt;strong&gt;product traceability&lt;/strong&gt;, building a complete history for every item, so you always know what went into it and how it was made. Finally, there are components for &lt;strong&gt;performance analysis&lt;/strong&gt;, showing you how well your production is running, and often for &lt;strong&gt;maintenance management&lt;/strong&gt; to help keep machines in good working order.&lt;/p&gt;
&lt;p&gt;These parts all connect to give you full control and insight into your manufacturing process.&lt;/p&gt;
&lt;h2 id=&quot;major-challenges-with-mes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#major-challenges-with-mes&quot;&gt;Major Challenges with MES&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While an MES offers huge benefits, putting one in place and getting the most out of it can have its challenges. It&#39;s important to know what these might be so you can plan for them.&lt;/p&gt;
&lt;p&gt;First and foremost challenge is cost and time to implement MES. Investing in an MES can be expensive upfront, including the software, hardware, and the considerable time it takes to set it up correctly across your factory. Beyond that, getting all your machines to talk to the MES can be complex, especially with older equipment from different manufacturers – it&#39;s like getting everyone to speak a single language. Another hurdle is changing how people work; employees may need significant training and can resist new ways of doing things. Also, choosing the right MES system from many options to perfectly fit your factory&#39;s unique needs can be tough. Finally, an MES needs ongoing care, updates, and adjustments as your factory changes. Without this, it might become outdated. Plus, the system is only as good as the data it gets; if the information isn&#39;t accurate, the MES won&#39;t provide reliable insights, making data quality a continuous effort.&lt;/p&gt;
&lt;h2 id=&quot;how-flowfuse-solves-these-challenges&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/what-is-mes/#how-flowfuse-solves-these-challenges&quot;&gt;How FlowFuse Solves These Challenges&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, how can we solve these problems, especially the ones related to getting started, integrating machines, and training people? This is exactly where FlowFuse steps in as a powerful solution. FlowFuse is a platform which directly addresses several of the major challenges we just discussed. Its visual, &amp;quot;drag and drop&amp;quot; interface means that engineers and factory personnel can build and deploy solutions much faster, significantly cutting down on the time and specialized talent usually needed for MES implementation and customization. This reduces the need for complex coding or developing deep programming skills.&lt;/p&gt;
&lt;p&gt;FlowFuse also excels at connecting diverse systems. Its vast library of nodes allows for easy integration with a wide range of industrial equipment, sensors, and existing IT systems, solving the complex problem of getting older machines or systems from different vendors to &amp;quot;talk&amp;quot; to each other without extensive custom development. This also enhances flexibility, as you can easily adapt and extend your MES functionality as your factory needs evolve. Furthermore, ensuring good data quality is made easier with the platform&#39;s powerful data transformation capabilities, allowing you to clean, filter, and structure raw data effortlessly, ensuring your MES always operates with accurate insights. By simplifying integration and development, and reducing the reliance on highly specialized coders, FlowFuse can dramatically lower the overall cost of implementing and maintaining an MES.&lt;/p&gt;
&lt;p&gt;In our upcoming articles, we will go deeper. We plan to explain and practically demonstrate how FlowFuse can be used to build your own MES, giving you the control and flexibility you need without the typical high investment or the need to buy a pre-packaged system. Stay tuned to see how you can create a tailored MES solution for your factory with FlowFuse.&lt;/p&gt;
&lt;p&gt;If you&#39;re ready to explore how FlowFuse can help you build a modern MES tailored to your factory, &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;get in touch&lt;/a&gt; with our team today. We&#39;d love to learn about your needs and help you take the next step toward a more efficient and profitable factory.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/</id>
        <title>FlowFuse 2.18: Smarter Monitoring, AI Integration, Improved DevOps, and a preview of exciting things to come</title>
        <summary>Monitor and improve instance performance, run AI chat in your Dashboard, Git pull, and more.</summary>
        <updated>2025-06-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release is focused on improvements that help you manage and optimize the performance of your Node-RED instances and takes an important step in integrating AI with FlowFuse so that you can build applications even more quickly.&lt;/p&gt;
&lt;h2 id=&quot;enhanced-observability-for-better-performance-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#enhanced-observability-for-better-performance-management&quot;&gt;Enhanced Observability for Better Performance Management&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Performance feature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/observability1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Performance Feature&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Understanding how your Node-RED instances perform is crucial for maintaining reliable applications. Our new observability feature provides detailed CPU usage metrics at both the instance and team levels, giving you the visibility needed to optimize performance and troubleshoot issues before they impact your operations.&lt;/p&gt;
&lt;p&gt;With these insights, you can make informed decisions about scaling your instances, identify performance bottlenecks, and ensure your Node-RED instances run smoothly in production environments. This feature is available exclusively for Enterprise customers, providing the enterprise-grade monitoring capabilities your organization needs.&lt;/p&gt;
&lt;h2 id=&quot;blueprint%3A-openai-llm-with-chat-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#blueprint%3A-openai-llm-with-chat-agent&quot;&gt;Blueprint: OpenAI LLM with Chat Agent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/Blueprint+-+Open+AI+Chat.mp4&quot; controls=&quot;&quot;&gt;&lt;/video&gt;
&lt;em&gt;Video of OpenAI LLM Blueprint demo&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We&#39;re bringing AI speed and power directly to your FlowFuse Dashboard. The new LLM Blueprint enables you to deploy an AI chat agent that can query and analyze data connected to your FlowFuse environment.&lt;/p&gt;
&lt;p&gt;This Blueprint makes it simple to surface insights relevant to your Node-RED flows, allowing team members to ask natural language questions and get immediate answers about their connected systems and devices. Whether you&#39;re monitoring sensor data, analyzing trends, or troubleshooting issues, the AI chat agent will speed up your workflow.&lt;/p&gt;
&lt;p&gt;Check out the video demo to see it in action, featuring the agent connected to a worldmap node!&lt;/p&gt;
&lt;p&gt;To put this Blueprint to use, check out the Blueprint page for &lt;a href=&quot;https://flowfuse.com/blueprints/ai/llm-chat-agent/&quot;&gt;OpenAI LLM Chat Agent.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;complete-git-integration-with-pull-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#complete-git-integration-with-pull-support&quot;&gt;Complete Git Integration with Pull Support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Building on our previous Git push functionality, we&#39;ve now added Git pull support, completing the core Git integration experience within FlowFuse.&lt;/p&gt;
&lt;p&gt;You can now seamlessly synchronize changes from your remote repositories, collaborate more effectively with team members, and maintain consistent version history across your Node-RED projects.&lt;/p&gt;
&lt;p&gt;More details are available in the &lt;a href=&quot;https://flowfuse.com/changelog/2025/06/git-integration/&quot;&gt;Git Integration changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;self-hosted-blueprint-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#self-hosted-blueprint-support&quot;&gt;Self-Hosted Blueprint Support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Organizations running self-hosted FlowFuse installations can now take advantage of the Blueprints we publish, bringing the same rapid development capabilities to on-premises and private cloud deployments.&lt;/p&gt;
&lt;p&gt;Self-hosted installations will automatically pull down the &lt;a href=&quot;https://flowfuse.com/blueprints/&quot;&gt;blueprint library&lt;/a&gt;, and will stay up to date when we publish new blueprints.&lt;/p&gt;
&lt;p&gt;This update ensures that all FlowFuse users, regardless of their deployment model, can benefit from our growing library of pre-built solutions.&lt;/p&gt;
&lt;h2 id=&quot;where-are-we-headed%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#where-are-we-headed%3F&quot;&gt;Where are we headed?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our Engineering team is hard at work on the next major developments in bringing the speed of AI to FlowFuse, developing AI functionality that will be integrated directly into the Node-RED editor. This upcoming feature set will dramatically accelerate your development process, helping you build and deploy applications faster than ever before.&lt;/p&gt;
&lt;p&gt;By combining AI assistance with Node-RED&#39;s visual programming approach, we&#39;re creating a development experience that&#39;s both more intuitive for newcomers and more powerful for experienced developers.&lt;/p&gt;
&lt;p&gt;Here is a sneak peek of something we&#39;re working on: an AI chat in the Node-RED editor that allows you to ask questions about the instance you are working in.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Preview of AI in Node-RED Editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/AI_preview.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.18 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Which feature do you think you&#39;re most likely to use? Email me directly and let me know! You can reach me at greg@flowfuse.com.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/flowfuse-release-2-18/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/</id>
        <title>Connect Your Shop Floor to Your ERP – Odoo Edition</title>
        <summary>Transform your operations by bringing real-time shop floor data directly into your ERP</summary>
        <updated>2025-06-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A major problem in manufacturing today is when your ERP system isn&#39;t getting real-time information from the factory floor. This gap causes big issues, like ordering too much material because inventory numbers are old, or missing important production deadlines. This lack of instant, correct information directly leads to higher costs and lost opportunities for your business.&lt;/p&gt;
&lt;p&gt;This problem often comes from old ways of recording data. Many factories still rely on paperwork, which takes up valuable space, and manual entries. These methods require extra human effort, causing big delays and added costs. These old, error-prone ways are simply not sustainable for modern manufacturing.&lt;/p&gt;
&lt;p&gt;This post gives you a vital solution. We&#39;ll show you how to connect your factory floor directly to your ERP system using FlowFuse. This way, you&#39;ll see near real-time data in your ERP, helping you avoid issues such as costly over-orders, missed deadlines, and the burdens of excessive paperwork. For this article, we&#39;ll focus on integrating with the popular ERP system, Odoo.&lt;/p&gt;
&lt;h2 id=&quot;basic-demo%3A-automating-production-data-from-the-shop-floor-to-odoo-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#basic-demo%3A-automating-production-data-from-the-shop-floor-to-odoo-with-flowfuse&quot;&gt;Basic Demo: Automating Production Data from the Shop Floor to Odoo with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start diving into how you can connect your shop floor to ERP, let&#39;s first see a simple demo. This basic demo shows how FlowFuse acts as a smart link, making sure your production line data is always accurate in your ERP. We&#39;re doing this with a Raspberry Pi running the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Agent&lt;/a&gt;, which talks to a Siemens S7 PLC. A counter in the PLC, which ticks up every second to act like products being made, is precisely read using the &lt;a href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/&quot;&gt;S7 protocol&lt;/a&gt; through FlowFuse. This accurate count is then automatically sent to Odoo as the quantity for a &amp;quot;table leg product,&amp;quot; keeping your inventory data always up-to-date.&lt;/p&gt;
&lt;p&gt;This is just a simple example of what FlowFuse can do. But it has much more power! Imagine FlowFuse also checking your production orders (MOs) in your ERP to see what you need to make. It can look at your Bills of Material (BOMs) in your ERP to figure out all the parts required. If it sees you&#39;re short on something, it can automatically create purchase orders in your ERP to buy the missing parts. It can even make new manufacturing orders for components you need to build.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;bxVq_8m-GOk&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;Below is the complete flow for this demo, in case you would like to explore it further or try it out yourself after reading the article&lt;/p&gt;
&lt;div id=&quot;nr-flow-217&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow217 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;cab977c8e0d1c054&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;6ba9343481e3b041&#92;&quot;,&#92;&quot;8a3adb31adbb7475&#92;&quot;,&#92;&quot;bfe37a946a6ed20a&#92;&quot;,&#92;&quot;304719d8be3f5694&#92;&quot;],&#92;&quot;x&#92;&quot;:664,&#92;&quot;y&#92;&quot;:399,&#92;&quot;w&#92;&quot;:732,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;6ba9343481e3b041&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-update&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cab977c8e0d1c054&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;product.template&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8a3adb31adbb7475&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cab977c8e0d1c054&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[[38],{&#92;&#92;&#92;&quot;qty_available&#92;&#92;&#92;&quot;:payload}]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1020,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6ba9343481e3b041&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bfe37a946a6ed20a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cab977c8e0d1c054&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Good Product Produced&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;304719d8be3f5694&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cab977c8e0d1c054&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;142c103a7735ea99&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Counter&#92;&quot;,&#92;&quot;diff&#92;&quot;:true,&#92;&quot;name&#92;&quot;:&#92;&quot;S7 &#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8a3adb31adbb7475&#92;&quot;,&#92;&quot;bfe37a946a6ed20a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;142c103a7735ea99&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 endpoint&#92;&quot;,&#92;&quot;transport&#92;&quot;:&#92;&quot;iso-on-tcp&#92;&quot;,&#92;&quot;address&#92;&quot;:&#92;&quot;192.168.1.6&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;102&#92;&quot;,&#92;&quot;rack&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;slot&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;localtsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;localtsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;remotetsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;remotetsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;connmode&#92;&quot;:&#92;&quot;rack-slot&#92;&quot;,&#92;&quot;adapter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;busaddr&#92;&quot;:2,&#92;&quot;cycletime&#92;&quot;:1000,&#92;&quot;timeout&#92;&quot;:2000,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;vartable&#92;&quot;:[{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X4.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,DW0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Counter&#92;&quot;}]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow217.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-217&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;getting-data-into-and-out-of-odoo-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#getting-data-into-and-out-of-odoo-with-flowfuse&quot;&gt;Getting Data Into and Out of Odoo with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will show you how you can connect your ERP (Odoo) with your shop floor using FlowFuse. This connection lets you read information, create new records, update existing ones, and search for specific data, bringing real-time factory insights right into your business system.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running FlowFuse Instance:&lt;/strong&gt; Make sure you have a FlowFuse instance set up and running. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-odoo-xmlrpc-filters-fields:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-odoo-xmlrpc-filters-fields&quot;&gt;node-red-contrib-odoo-xmlrpc-filters-fields&lt;/a&gt; installed. This package will enable operations like reading, creating, updating, and searching data, with specific capabilities for filtering records and selecting precise fields.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;configuring-the-odoo-connection-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#configuring-the-odoo-connection-node&quot;&gt;Configuring the Odoo Connection Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you can send or receive any data from Odoo, FlowFuse needs to know how to connect to your Odoo instance. This is a one-time setup for your connection details, which can then be reused across all your Odoo nodes in FlowFuse.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag any &lt;code&gt;odoo-xmlrpc&lt;/code&gt; node (like &lt;code&gt;odoo-xmlrpc-read&lt;/code&gt; or &lt;code&gt;odoo-xmlrpc-create&lt;/code&gt;) onto your Node-RED canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node to open its configuration.&lt;/li&gt;
&lt;li&gt;Next to the &amp;quot;Host&amp;quot; field, click the pencil icon to add a new Odoo connection.&lt;/li&gt;
&lt;li&gt;In the configuration dialog, you&#39;ll need to enter your Odoo instance&#39;s details:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Host URL: This is the web address of your Odoo instance (e.g., &lt;code&gt;https://databaseName.odoo.com&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Database: The name of your Odoo database.&lt;/li&gt;
&lt;li&gt;Username: Your Odoo login username (e.g., your email address).&lt;/li&gt;
&lt;li&gt;Password: Your Odoo login password.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &amp;quot;Add&amp;quot; to save this configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Configuring Odoo Node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/configuration-odoo.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring Odoo Node&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, any &lt;code&gt;odoo-xmlrpc&lt;/code&gt; node you use can select this saved host configuration, meaning you only have to enter your credentials once.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: These configuration details (Host, Database, Username, Password) are confidential. To prevent exposing them when sharing your flows, it&#39;s crucial to use &lt;strong&gt;FlowFuse Environment Variables&lt;/strong&gt;. These variables allow you to store sensitive information securely outside of your flow code. For more information, refer to our guide on &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Environment Variables in Node-RED&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;understanding-odoo-models&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#understanding-odoo-models&quot;&gt;Understanding Odoo Models&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your connection is set up, the next key concept for interacting with Odoo is understanding &lt;strong&gt;Models&lt;/strong&gt;. In Odoo, a &amp;quot;model&amp;quot; represents a specific type of business object or data record, much like a table in a traditional database. Every piece of data you want to read, create, update, or delete belongs to a specific model.&lt;/p&gt;
&lt;p&gt;Common Odoo models relevant to manufacturing include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;product.template&lt;/code&gt;: For general product information (e.g., product names, descriptions).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stock.quant&lt;/code&gt;: For inventory quantities and locations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mrp.production&lt;/code&gt;: For manufacturing orders/production orders.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;res.partner&lt;/code&gt;: For contacts (customers, suppliers).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stock.picking&lt;/code&gt;: For internal transfers or delivery orders.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you use an &lt;code&gt;odoo-xmlrpc&lt;/code&gt; node in FlowFuse, you&#39;ll always need to specify which &lt;code&gt;model&lt;/code&gt; you want to work with. If you&#39;re unsure of a specific model&#39;s name, you can often find it by enabling &amp;quot;Developer Mode&amp;quot; in your Odoo instance and hovering over fields in the Odoo interface.&lt;/p&gt;
&lt;p&gt;Let’s get started. When explaining each operation, I will demonstrate it using different models such as &lt;code&gt;product.product&lt;/code&gt; or &lt;code&gt;mrp.production&lt;/code&gt;. This is just for demonstration and your understanding. You can perform these operations in the same way with other models—just make sure to pass the correct parameters according to the model and its data.&lt;/p&gt;
&lt;h3 id=&quot;reading-data-from-odoo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#reading-data-from-odoo&quot;&gt;Reading Data from Odoo&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To read data from Odoo, you&#39;ll use the &lt;code&gt;odoo-xmlrpc-search_read&lt;/code&gt; node. This node requires you to send the id (or ids) of the record(s) you wish to read to this node with &lt;code&gt;msg.payload&lt;/code&gt;. The &lt;code&gt;msg.payload&lt;/code&gt; should contain an array of the IDs you want to read.&lt;/p&gt;
&lt;p&gt;Here is how you can read products data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas.&lt;/li&gt;
&lt;li&gt;Connect it to a change node. Here, you&#39;ll set the query details:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the following array:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-185&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-185&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ID&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-185&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Replace ID with the actual product ID you want to read. You can include multiple IDs, for example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-189&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-189&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-189&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Connect the change node to an odoo-xmlrpc-search_read node. Select your Odoo connection, enter model to &lt;code&gt;product.product&lt;/code&gt; (or the Odoo model you want to query).&lt;/li&gt;
&lt;li&gt;Connect to a debug node to view the data.&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject node button to see the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;9CdVOp_bDMk&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-218&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow218 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;4f2bd9814f07c6a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-read&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;product.template&#92;&quot;,&#92;&quot;x&#92;&quot;:1190,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5601affdba752326&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5601affdba752326&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 6&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1500,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4e8b22877e33b496&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read products with id 23 and 39&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b21cdd78ad81d65a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b21cdd78ad81d65a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[39,23]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4f2bd9814f07c6a6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${HOST}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${USERNAME} &#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow218.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-218&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;creating-new-record-in-odoo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#creating-new-record-in-odoo&quot;&gt;Creating New Record in Odoo&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To create new records in Odoo using FlowFuse, use the &lt;code&gt;odoo-xmlrpc-create&lt;/code&gt; node. This node requires you to send an array of objects containing the record information as &lt;code&gt;msg.payload&lt;/code&gt;. The array can include multiple objects, allowing you to create multiple records at once.&lt;/p&gt;
&lt;p&gt;Here is how you can create manufacturing order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas and set it to trigger manually.&lt;/li&gt;
&lt;li&gt;Connect it to a change node. Configure it to set &lt;code&gt;msg.payload&lt;/code&gt; with the details for your new Odoo manufacturing order:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-239&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-239&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;product_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;39&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;      &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;product_qty&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;     &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;product_uom_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-239&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the change node to an &lt;code&gt;odoo-xmlrpc-create&lt;/code&gt; node. Select your configured Odoo connection for its Host and enter model to &lt;code&gt;mrp.production&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Connect the &lt;code&gt;odoo-xmlrpc-create node&lt;/code&gt; to a debug node to see the ID of the new record Odoo creates.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;bq_yaF8etmw&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-219&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow219 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d89d98a5ec9a8733&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-create&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;mrp.production&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:1200,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ea101f5cab65a241&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;99ba2ffda10cf2d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create New MO&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;33e0301b6e8f7838&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ea101f5cab65a241&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 5&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1500,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;33e0301b6e8f7838&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[{&#92;&#92;&#92;&quot;product_id&#92;&#92;&#92;&quot;:30,&#92;&#92;&#92;&quot;product_qty&#92;&#92;&#92;&quot;:200,&#92;&#92;&#92;&quot;product_uom_id&#92;&#92;&#92;&quot;:1}]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d89d98a5ec9a8733&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${HOST}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${USERNAME} &#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow219.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-219&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;updating-existing-data-in-odoo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#updating-existing-data-in-odoo&quot;&gt;Updating Existing Data in Odoo&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To modify existing records in Odoo using FlowFuse, you&#39;ll use the &lt;code&gt;odoo-xmlrpc-update&lt;/code&gt; node. This node requires the ID of the record(s) you want to update and the new values for the fields you wish to change. The &lt;code&gt;msg.payload&lt;/code&gt; should contain an array, where the first element is a list of record IDs and the second element is an object with the fields to update.&lt;/p&gt;
&lt;p&gt;Here is how you can update the status of manufacturing order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas. Configure it to trigger manually.&lt;/li&gt;
&lt;li&gt;Connect it to a change node. This node will prepare the &lt;code&gt;msg.payload&lt;/code&gt; with the order ID and the new status.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to :&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-284&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-284&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;state&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-284&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the change node to an &lt;code&gt;odoo-xmlrpc-update&lt;/code&gt; node. Select your configured Odoo connection for its Host and enter model to &lt;code&gt;mrp.production&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Connect the &lt;code&gt;odoo-xmlrpc-update&lt;/code&gt; node to a debug node to confirm the update operation. (A successful update typically returns true or an empty payload).&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject node button to see the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;SsPfHxCwMI8&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-220&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow220 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;e43dc05eb7df7ecf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update MO Status&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;11bbd21f1314b839&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;47b01f56b4800c5c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1500,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bd9de404f2ac1a2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-update&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;mrp.production&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:1200,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;47b01f56b4800c5c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;11bbd21f1314b839&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[     [18],     {&#92;&#92;&#92;&quot;state&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;progress&#92;&#92;&#92;&quot;} ]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bd9de404f2ac1a2e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${HOST}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${USERNAME} &#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow220.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-220&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;deleting-records-from-odoo-(unlink)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#deleting-records-from-odoo-(unlink)&quot;&gt;Deleting Records from Odoo (Unlink)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To delete records in Odoo using FlowFuse, you&#39;ll use the &lt;code&gt;odoo-xmlrpc-unlink&lt;/code&gt; node. This node requires you to send the id (or ids) of the record(s) you wish to remove. The &lt;code&gt;msg.payload&lt;/code&gt; should contain an array of the IDs you want to delete.&lt;/p&gt;
&lt;p&gt;Here is how you can delete product from inventory:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas. Configure it to trigger manually.&lt;/li&gt;
&lt;li&gt;Connect the inject node to a change node. This node will prepare the msg.payload with the ID(s) of the record(s) to delete.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to a JSON array containing the ID of the manufacturing order to delete:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-334&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-334&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-334&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the change node to an &lt;code&gt;odoo-xmlrpc-unlink&lt;/code&gt;. Select your configured Odoo connection for its Host and enter model to &lt;code&gt;mrp.production&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Connect the &lt;code&gt;odoo-xmlrpc-unlink&lt;/code&gt; to a debug node to confirm the unlink operation.&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject node button to see the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;1O1JYRtX-Sg&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-221&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow221 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;f14241bb24af8dc8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-unlink&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;product.template&#92;&quot;,&#92;&quot;x&#92;&quot;:1190,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;231e32e70753ab22&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9452d125fd059f79&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Delete the product with ID 60&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:580,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cfcabeae8b291a9c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;231e32e70753ab22&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 7&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1500,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cfcabeae8b291a9c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[60]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f14241bb24af8dc8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${HOST}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${USERNAME} &#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow221.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-221&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;advanced-search-with-filters-and-fields&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#advanced-search-with-filters-and-fields&quot;&gt;Advanced Search with Filters and Fields&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For advanced queries, you&#39;ll use the &lt;code&gt;odoo-xmlrpc-search_read&lt;/code&gt; node. This versatile node combines the ability to search for records using complex criteria (filters) and to retrieve only the specific data fields you need from those results.&lt;/p&gt;
&lt;h4 id=&quot;understanding-filters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#understanding-filters&quot;&gt;Understanding Filters&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Filters are conditions you apply to narrow down your search results. They are structured as a &lt;strong&gt;list of lists&lt;/strong&gt;, where each inner list defines a single condition: &lt;code&gt;[field, operator, value]&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;field&lt;/code&gt;: The name of the Odoo field you want to filter by (e.g., &lt;code&gt;qty_available&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;operator&lt;/code&gt;: How you want to compare the field. Common operators include:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt;: Equal to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!=&lt;/code&gt;: Not equal to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;: Greater than&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;: Less than&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;=&lt;/code&gt;: Greater than or equal to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;=&lt;/code&gt;: Less than or equal to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;in&lt;/code&gt;: Value is in a list (e.g., &lt;code&gt;[[&amp;quot;id&amp;quot;, &amp;quot;in&amp;quot;, [1, 2, 3]]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;not in&lt;/code&gt;: Value is not in a list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ilike&lt;/code&gt;: Case-insensitive &amp;quot;like&amp;quot; (contains substring)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=like&lt;/code&gt;: Case-sensitive &amp;quot;like&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;: The value you&#39;re comparing against.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you include multiple conditions within your filters list, Odoo treats them as an &amp;quot;AND&amp;quot; relationship by default. This means all conditions must be true for a record to be returned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example Filters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[[&amp;quot;list_price&amp;quot;, &amp;quot;&amp;lt;&amp;quot;, 10]]]&lt;/code&gt;: Find products with less than 10 units in stock.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[[[&amp;quot;state&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;progress&amp;quot;], [&amp;quot;product_id&amp;quot;, &amp;quot;=&amp;quot;, 38]]]&lt;/code&gt;: Find manufacturing orders for a specific product that are currently &amp;quot;in progress.&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[[[&amp;quot;name&amp;quot;, &amp;quot;ilike&amp;quot;, &amp;quot;coating&amp;quot;]]]&lt;/code&gt;: Find products where the name contains &amp;quot;coating&amp;quot; (case-insensitive).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;understanding-fields&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#understanding-fields&quot;&gt;Understanding Fields&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;fields&lt;/code&gt; parameter allows you to specify exactly which columns or properties you want to retrieve for the matching records. This is important for efficiency, as it avoids pulling unnecessary data, making your flows faster and your payloads smaller.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structure:&lt;/strong&gt; A simple list of field names (e.g., &lt;code&gt;[&amp;quot;name&amp;quot;, &amp;quot;qty_available&amp;quot;, &amp;quot;default_code&amp;quot;]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;controlling-results%3A-offset-and-limit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#controlling-results%3A-offset-and-limit&quot;&gt;Controlling Results: Offset and Limit&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For larger datasets, you&#39;ll want to control how many records are returned and where the results start.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;offset: This parameter specifies the number of records to skip from the beginning of the result set. It&#39;s useful for pagination.&lt;/li&gt;
&lt;li&gt;limit: This parameter specifies the maximum number of records to return in a single query. It&#39;s crucial for managing the amount of data you retrieve.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;example-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#example-flow&quot;&gt;Example Flow&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Here’s an example FlowFuse flow to find products with list price (more than 1000) that are also marked as &amp;quot;saleable&amp;quot; in Odoo, retrieving only their name, quantity, internal reference, and list price, and limiting the results.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto your canvas and configure it to trigger manually.&lt;/li&gt;
&lt;li&gt;Connect it to a change node. This node will define your search criteria (filters and fields) and also set the offset and limit.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.filters&lt;/code&gt; to JSON:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-516&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-516&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;list_price&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sale_ok&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;=&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-516&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.fields&lt;/code&gt; to JSON:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-524&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-524&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;qty_available&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;default_code&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;standard_price&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-524&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.offset&lt;/code&gt; to Number 0 (Start from the first record).&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.limit&lt;/code&gt; to Number 5 (Retrieve a maximum of 10 records).&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the change node to an &lt;code&gt;odoo-xmlrpc-search_read&lt;/code&gt; node. Select your configured Odoo connection.&lt;/li&gt;
&lt;li&gt;Connect to a debug node to inspect the filtered and selected data in the debug sidebar.&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject node button to see the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;8Asa3z2VctQ&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-222&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow222 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;0cfe26fd5b4169e7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 4&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1500,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;656023449ba5dee9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Top 5 Saleable Products &amp;gt;1000&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7f791bfc8caa0721&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8ada5a972d94dd9d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-search-read&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;host&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;model&#92;&quot;:&#92;&quot;product.product&#92;&quot;,&#92;&quot;filter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;limit&#92;&quot;:100,&#92;&quot;x&#92;&quot;:1210,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0cfe26fd5b4169e7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7f791bfc8caa0721&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;295d40790bd21f48&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;filters&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[[[&#92;&#92;&#92;&quot;list_price&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;&#92;&quot;,1000],[&#92;&#92;&#92;&quot;sale_ok&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;=&#92;&#92;&#92;&quot;,true]]]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;limit&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;offset&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;fields&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[&#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;qty_available&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;default_code&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;lst_price&#92;&#92;&#92;&quot;]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8ada5a972d94dd9d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18818bdefd1f27ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;odoo-xmlrpc-config&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${HOST}&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;${DB_NAME}&#92;&quot;,&#92;&quot;username&#92;&quot;:&#92;&quot;${USERNAME} &#92;&quot;,&#92;&quot;password&#92;&quot;:&#92;&quot;${PASSWORD}&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow222.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-222&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;final-thought&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/06/connect-shop-floor-to-odoo-erp-flowfuse/#final-thought&quot;&gt;Final thought&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, we&#39;ve talked about how those manual data methods—paper, spreadsheets—can really slow things down, cause mistakes, and cost money in your factory. And let&#39;s be honest, many digital fixes out there just add more complexity or demand specialized coding skills that your team might not have.&lt;/p&gt;
&lt;p&gt;This is where FlowFuse comes in. FlowFuse is a platform made for factory floors that runs on your devices right there. It connects to all your machines, old or new, and even your ERP systems like Odoo. FlowFuse collects, cleans, and moves your data. It helps your engineers, who know your operations best, build industrial applications and solutions using simple drag-and-drop actions. This means they can link your factory data directly to your ERP, getting rid of all those manual steps and saving your IT team time and money.&lt;/p&gt;
&lt;p&gt;What&#39;s the real payoff? You get to see less wasted time and money, fewer mistakes with accurate, real-time data, and simply better control over your whole factory. FlowFuse helps your entire operation run smarter and more reliably. If you&#39;re looking for a practical way to bring these kinds of improvements to your own manufacturing processes, we&#39;d be glad to discuss how FlowFuse can assist. &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Get in touch here&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/</id>
        <title>Building a Flexible Node-RED Scheduler with Cron-Plus</title>
        <summary>Go Beyond Inject Nodes: Automate Smarter with Flexible Cron Schedules in Node-RED</summary>
        <updated>2025-05-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Automation isn’t just about reacting to events—sometimes it’s about doing things at the right time. In Node-RED, the Inject node is great for triggering flows at set intervals, but it’s limited when you need more control. Cron jobs offer precise scheduling, letting you set up custom times for your tasks. In this guide, we&#39;ll show you how to create flexible cron schedules in FlowFuse with Node-RED, so your flows run exactly when needed.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-cron-job%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#what-is-a-cron-job%3F&quot;&gt;What is a Cron Job?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s kick things off by demystifying what a cron job actually is. You’ve probably heard the term before, and while it might sound complex, it’s really just a way of setting up tasks to run at specific times — automatically.&lt;/p&gt;
&lt;p&gt;Think of it this way: with Node-RED’s Inject node, you can trigger tasks at intervals like every 5 seconds, every minute, or even on specific weekdays at set times (for example, every Monday, Tuesday, or Sunday). But when you use cron jobs, you gain much more control over the timing.&lt;/p&gt;
&lt;p&gt;For example, you can trigger a task every two hours, only on weekdays, but skip holidays or run a job every 5 minutes during business hours, but only in the first week of each quarter. You can even schedule flows to run at 6:45 AM on the last Friday of every month, or at 11:59 PM on the last day of the year — these kinds of patterns are either extremely complex or completely unachievable using just the Inject node.&lt;/p&gt;
&lt;p&gt;The magic of cron lies in its ability to express complex time logic in a simple, compact format — perfect for orchestrating automation schedules that go well beyond what the basic Inject node can offer.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start building flexible cron schedules in FlowFuse, make sure you have the following in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running FlowFuse Instance:&lt;/strong&gt; Make sure you have a FlowFuse instance set up and running. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; and learn how to create an instance in FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-cron-plus:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-cron-plus&quot;&gt;node-red-contrib-cron-plus&lt;/a&gt; installed, It’s developed by Steve, a software engineer here at FlowFuse and one of the core maintainers of Node-RED.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-scheduled-automations-with-cron-plus&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#building-scheduled-automations-with-cron-plus&quot;&gt;Building Scheduled Automations with cron-plus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand what cron jobs are and why they’re useful, let’s dive into building them inside Node-RED using the cron-plus node. When working with cron-plus, you’ll encounter different types of schedules—each suited for different needs—and varying levels of complexity depending on what you&#39;re trying to automate.&lt;/p&gt;
&lt;p&gt;At the most basic level, you can define static schedules using familiar cron expressions (like &amp;quot;every 5 minutes&amp;quot; or &amp;quot;at 8:00 AM daily&amp;quot;). As you progress, you’ll learn to use solar event triggers (like sunrise or sunset), create date-specific schedules, and even manage schedules dynamically at runtime—adding, removing, or modifying them based on incoming data or user interactions.&lt;/p&gt;
&lt;p&gt;In this section, we’ll walk through each of these layers step by step, starting with the simplest use cases and gradually moving into more powerful and flexible scheduling techniques—giving you full control over when and how your flows run.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: This article draws information from the node’s &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-cron-plus&quot;&gt;README&lt;/a&gt;, which is highly informative. I recommend going through it as well for more details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;static-schedules&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#static-schedules&quot;&gt;Static Schedules&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The most straightforward way to use cron-plus is to define static schedules using cron expressions. These are pre-configured inside the node and run on a fixed pattern—perfect for predictable, repetitive tasks. For example we need to Trigger a flow every day at 8:00 AM.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag and drop the cron-plus node onto your Node-RED workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click on the cron-plus node to open its configuration panel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If no schedules are configured yet, click the +add button to add a new schedule. Enter the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Schedule Name: e.g., &amp;quot;Daily 8 AM&amp;quot;&lt;/li&gt;
&lt;li&gt;Topic: Enter a topic to send with the message when triggered, such as &amp;quot;daily-trigger&amp;quot;.&lt;/li&gt;
&lt;li&gt;Payload: Choose what payload you want to send when the cron job triggers, such as &amp;quot;Triggering Flow at 8 AM&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select Cron from the Schedule Type dropdown.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the Schedule field, enter the following cron expression to run the task at 8:00 AM every day:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   0 8 * * *
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A cron expression is composed of five fields (sometimes six or seven, depending on the system) that determine the schedule for executing tasks.
Below is a breakdown of each field that node-red-contrib-cron-plus supports:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Possible Values&lt;/th&gt;
&lt;th&gt;Special Symbols&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Second  (optional)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0-59&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minute&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0-59&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hour&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0-23&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day of Month&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1-31&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , - ? L W&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1-12&lt;/code&gt; or &lt;code&gt;JAN-DEC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day of Week&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0-6&lt;/code&gt; or &lt;code&gt;SUN-SAT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , - ? L #&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Year (optional)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1970-2099&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* / , -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here are some examples of how you can use the special symbols and shorthand&#39;s:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All possible values&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* * * * *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every minute of every hour, day, month, and weekday&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No specific value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 12 ? * MON&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;At 12 PM Only on Mondays (no specific day of the month)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Range&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 10-12 * * * *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minutes 10, 11, and 12 of every hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;,&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List of values&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 12 * 1,3,5 *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;At 12 PM only in January, March, and May&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Step values&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*/15 * * * *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every 15 minutes (00, 15, 30, 45)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Last&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 12 L * *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12 PM on the last day of the month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nearest weekday&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 0 15W * * *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;At midnight on the nearest weekday to the 15th of the month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nth weekday of the month&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 0 * * MON#1 *&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;At midnight on the first Monday of the month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the cron-plus node to other nodes (e.g., a debug node or an action node) to specify the actions when the flow is triggered.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Deploy to save and activate your flow. The cron-plus node will now trigger your flow every day at 8:00 AM.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-210&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow210 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;2af2e9274fe1321a&#92;&quot;,&#92;&quot;458c9533a1437ee1&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:392,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;2af2e9274fe1321a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;458c9533a1437ee1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cronplus&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Cron Plus&#92;&quot;,&#92;&quot;outputField&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;timeZone&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;storeName&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;commandResponseMsgOutput&#92;&quot;:&#92;&quot;output1&#92;&quot;,&#92;&quot;defaultLocation&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;defaultLocationType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;options&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Daily 8 AM&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;daily-trigger&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expressionType&#92;&quot;:&#92;&quot;cron&#92;&quot;,&#92;&quot;expression&#92;&quot;:&#92;&quot; 0 8 * * *&#92;&quot;,&#92;&quot;location&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;solarType&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;solarEvents&#92;&quot;:&#92;&quot;sunrise,sunset&#92;&quot;}],&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2af2e9274fe1321a&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow210.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-210&#39;) })&lt;/script&gt;
&lt;p&gt;Here are some advance patterns:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every weekday at 9:30 AM&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;30 9 * * 1-5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every hour&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 * * * *
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every 15 min during work hours (Mon–Fri, 9–5)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*/15 9-16 * * 1-5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;First Monday of the month at 10:00 AM&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 10 * * MON#1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Last Friday of the month at 6:45 AM&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;45 6 ? * FRIL
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;easy-builder-feature&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#easy-builder-feature&quot;&gt;Easy Builder Feature&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To make it even easier to create and customize cron patterns, the cron-plus node includes a feature called Easy Builder. This feature provides a user-friendly interface that lets you quickly generate and adjust cron expressions without needing to write them manually. You can select options like time intervals, days of the week, and more, and the Easy Builder will generate the correct cron syntax for you.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the easy builder feature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/easy-builder.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the easy builder feature&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;solar-event-schedules&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#solar-event-schedules&quot;&gt;Solar Event Schedules&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Solar event-based triggers are a great feature in cron-plus for automating tasks based on sunlight events like sunrise, sunset, dawn, and dusk. You can fine-tune your triggers with offsets, like triggering an action 30 minutes after sunset.&lt;/p&gt;
&lt;p&gt;Here are the solar events you can use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;nightEnd&lt;/strong&gt;: End of night, start of twilight.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nauticalDawn&lt;/strong&gt;: Horizon becomes faintly visible, used by sailors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;civilDawn&lt;/strong&gt;: Light enough for outdoor activities without lights.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sunrise&lt;/strong&gt;: Sun first visible on the horizon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sunriseEnd&lt;/strong&gt;: Full sun above the horizon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;morningGoldenHourEnd&lt;/strong&gt;: End of the morning golden hour.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;solarNoon&lt;/strong&gt;: Sun is at its highest point in the sky.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;eveningGoldenHourStart&lt;/strong&gt;: Start of the evening golden hour.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sunsetStart&lt;/strong&gt;: Sun starts to set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sunset&lt;/strong&gt;: Sun is fully below the horizon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;civilDusk&lt;/strong&gt;: Last light before it gets dark.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nauticalDusk&lt;/strong&gt;: Horizon is no longer visible, dark sky.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nightStart&lt;/strong&gt;: Full darkness after twilight.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nadir&lt;/strong&gt;: Darkest point of the night.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&#39;s start and learn how to use it. Suppose we need to trigger the flow 30 minutes after sunset. Here&#39;s how you do it:&lt;/p&gt;
&lt;p&gt;Let’s start by setting up a flow that triggers 30 minutes after sunset. Here’s how:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a new &lt;code&gt;cron-plus&lt;/code&gt; node onto your Node-RED canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the location — solar events depend on your geographic location. You can configure this at the node level or per schedule. In the Location field, either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enter your latitude and longitude manually, or&lt;/li&gt;
&lt;li&gt;Click the three-dot icon to open a map and select your location.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a new schedule. Enter the following Schedule Name, Topic, Payload&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose the solar event — set the Schedule Type to &lt;code&gt;solar&lt;/code&gt;.&lt;br /&gt;
You can choose &amp;quot;All Solar Events&amp;quot; or &amp;quot;Selected Solar Events&amp;quot; to pick specific ones.&lt;br /&gt;
For this example, choose &amp;quot;sunset&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the offset — this defines how much earlier or later the trigger should happen compared to the solar event.&lt;br /&gt;
For 30 minutes after sunset, enter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also use negative numbers (like &lt;code&gt;-10&lt;/code&gt; for 10 minutes before sunset) or larger values like &lt;code&gt;60&lt;/code&gt; for 1 hour after.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Done, connect the node to the rest of your flow, and Deploy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-211&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow211 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;2af2e9274fe1321a&#92;&quot;,&#92;&quot;458c9533a1437ee1&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:392,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;2af2e9274fe1321a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;458c9533a1437ee1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cronplus&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;cba15bd32c5434a5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Cron Plus&#92;&quot;,&#92;&quot;outputField&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;timeZone&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;storeName&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;commandResponseMsgOutput&#92;&quot;:&#92;&quot;output1&#92;&quot;,&#92;&quot;defaultLocation&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;defaultLocationType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;options&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;et&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;30min After Sunset&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expressionType&#92;&quot;:&#92;&quot;solar&#92;&quot;,&#92;&quot;expression&#92;&quot;:&#92;&quot; 0 8 * * *&#92;&quot;,&#92;&quot;location&#92;&quot;:&#92;&quot;20.70816594524601 75.673828125&#92;&quot;,&#92;&quot;offset&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;solarType&#92;&quot;:&#92;&quot;selected&#92;&quot;,&#92;&quot;solarEvents&#92;&quot;:&#92;&quot;sunset&#92;&quot;}],&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2af2e9274fe1321a&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow211.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-211&#39;) })&lt;/script&gt;
&lt;p&gt;Your flow will now trigger 30 minutes after sunset every day — automatically adjusting for seasonal changes based on your location.&lt;/p&gt;
&lt;h3 id=&quot;date-sequence-schedules&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#date-sequence-schedules&quot;&gt;Date Sequence Schedules&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While cron expressions and solar events are great for recurring patterns, sometimes you need to schedule flows to run at very specific, one-time moments—like a product launch, system maintenance window, or a holiday-specific action. This is where the Date Sequence schedule type in cron-plus comes in.&lt;/p&gt;
&lt;p&gt;With this method, you can define exact dates and times (including timezone support), and the node will trigger your flow at those precise moments—once or multiple times, depending on the list you define.&lt;/p&gt;
&lt;p&gt;The sequence field supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UNIX timestamps (in milliseconds)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;1767225600000 
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Date and time (in plain text)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;2026-04-03 00:00
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Date and time with timezone&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;2026-04-06 12:00 GMT+0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can list multiple times, separated by commas:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1767225600000, 2026-04-03 00:00, 2026-04-06 12:00 GMT+0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s learn how to set this up:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a new cron-plus node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its settings.&lt;/li&gt;
&lt;li&gt;Click +add to create a new schedule.&lt;/li&gt;
&lt;li&gt;Give the schedule a name and configure the topic — this is the value that will be sent with the message when the schedule triggers.&lt;/li&gt;
&lt;li&gt;Set the payload to whatever message or data you want to send when triggered.&lt;/li&gt;
&lt;li&gt;Choose Date Sequence from the Schedule Type dropdown.&lt;/li&gt;
&lt;li&gt;In the Expression field, enter one or more dates using any of the 8. supported formats we discussed above (UNIX timestamp, plain date/time, or date/time with timezone). You can separate multiple values with commas.&lt;/li&gt;
&lt;li&gt;Click Done, then connect the cron-plus node to the rest of your flow (e.g., a debug node to see it trigger, or an action node to perform something).&lt;/li&gt;
&lt;li&gt;Finally, click Deploy to save and start your schedule.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-212&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow212 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2ff341cec3114c53&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cronplus&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;2aa2d59a36bf0fa7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Date Sequence&#92;&quot;,&#92;&quot;outputField&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;timeZone&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;storeName&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;commandResponseMsgOutput&#92;&quot;:&#92;&quot;output1&#92;&quot;,&#92;&quot;defaultLocation&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;defaultLocationType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;options&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;schedule1&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;fixed dates&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;expressionType&#92;&quot;:&#92;&quot;dates&#92;&quot;,&#92;&quot;expression&#92;&quot;:&#92;&quot;1767225600000, 2026-04-03 00:00, 2026-04-06 12:00 GMT+0&#92;&quot;,&#92;&quot;location&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offset&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;solarType&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;solarEvents&#92;&quot;:&#92;&quot;sunrise,sunset&#92;&quot;}],&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b66ebe91df84b4ce&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b66ebe91df84b4ce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;2aa2d59a36bf0fa7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:560,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow212.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-212&#39;) })&lt;/script&gt;
&lt;p&gt;The flow will now trigger exactly at each date and time you&#39;ve specified.&lt;/p&gt;
&lt;h3 id=&quot;handling-time-zones-and-daylight-saving-time-(dst)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#handling-time-zones-and-daylight-saving-time-(dst)&quot;&gt;Handling Time Zones and Daylight Saving Time (DST)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When dealing with scheduled tasks, managing time zones and Daylight Saving Time (DST) is crucial to ensure your cron jobs trigger at the correct local time. With cron-plus in Node-RED, this is made easy. Cron-plus provides global time zone support, allowing you to specify the time zone for all schedules within a particular cron-plus node. When configuring the cron-plus node, you&#39;ll see an input field labeled &amp;quot;Timezone&amp;quot;, where you can start typing your desired time zone and select from suggested options.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Timezone input field in the cron-plus node configuration with auto-suggestions while typing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/timezone-selection.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the Timezone input field in the cron-plus node configuration with auto-suggestions while typing&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For example, if your tasks need to run in the Eastern Time Zone, you would enter &amp;quot;America/New_York&amp;quot; in the Timezone field. Similarly, for the UK time zone, you would enter &amp;quot;Europe/London&amp;quot;.&lt;/p&gt;
&lt;p&gt;When scheduling tasks in a time zone that observes Daylight Saving Time (DST), cron-plus will automatically adjust your task’s execution times to account for the DST changes. If you set a schedule for 8:00 AM daily, cron-plus will ensure that the task triggers at 8:00 AM local time, whether it&#39;s during Standard Time (e.g., EST) or Daylight Saving Time (e.g., EDT).&lt;/p&gt;
&lt;p&gt;When DST begins (e.g., in spring), cron-plus will shift the scheduled task forward by one hour. Similarly, when DST ends (e.g., in fall), the task will shift back by one hour. This automatic adjustment is handled based on the time zone you enter.&lt;/p&gt;
&lt;h3 id=&quot;understanding-node-status-symbols-and-their-descriptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#understanding-node-status-symbols-and-their-descriptions&quot;&gt;Understanding Node Status Symbols and Their Descriptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The cron-plus node visually indicates its state using status markers in the flow editor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;● (Dot):&lt;/strong&gt; Indicates a static schedule configured directly in the node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;○ (Ring):&lt;/strong&gt; Indicates a dynamic schedule added via input messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, the node indicates the next event, along with the type of schedule. For example, node in the following image specifies that the next event is on May 26, 2025, at 12:00 AM GMT +5:30. It is a static schedule, and its name is &#39;Schedule1&#39;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A node showing the next event scheduled for May 26, 2025, at 12:00 AM GMT +5:30 with a static schedule named &#39;Schedule1&#39;.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-status-event.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A node showing the next event scheduled for May 26, 2025, at 12:00 AM GMT +5:30 with a static schedule named &#39;Schedule1&#39;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;dynamic-schedule-control-via-input-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#dynamic-schedule-control-via-input-messages&quot;&gt;Dynamic Schedule Control via Input Messages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In some cases, you might not know your schedule ahead of time—or you may want it to change based on user actions or incoming data. The cron-plus node supports this with dynamic control using input messages. This means you can add, update, or remove schedules while your flow is running, without opening the editor. It’s a powerful way to make your automations more responsive and adaptable.&lt;/p&gt;
&lt;p&gt;Each control message is sent to the &lt;code&gt;cron-plus&lt;/code&gt; node using a specially formatted &lt;code&gt;msg.payload&lt;/code&gt; with a command and associated configuration.&lt;/p&gt;
&lt;p&gt;Below are some examples of dynamic commands. Please refer to the built-in help of the cron-plus node for more details:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trigger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Triggers a schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;trigger&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add (or update) a dynamic schedule.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;add&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot;, &amp;quot;topic&amp;quot;: &amp;quot;dynamic-schedule&amp;quot;, &amp;quot;payloadType&amp;quot;: &amp;quot;default&amp;quot;, &amp;quot;expressionType&amp;quot;: &amp;quot;cron&amp;quot;, &amp;quot;expression&amp;quot;: &amp;quot;*/2 * * * *&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes a specific schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;remove&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Starts a specific schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;start&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stops a specific schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;stop&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pause&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pauses a specific schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;pause&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;export&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exports a schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;export&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provides the status of a specific schedule by name.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;status&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;dynamic-1&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;describe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provides a human-readable description of a cron or solar expression.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;describe&amp;quot;, &amp;quot;expression&amp;quot;: &amp;quot;0 8 * * 1-5&amp;quot;, &amp;quot;expressionType&amp;quot;: &amp;quot;cron&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Commands can also include a &lt;code&gt;filter&lt;/code&gt; to operate on multiple schedules at once. Below are a few examples. Please refer to the built-in help of the cron-plus node for more details:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;start-all&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-dynamic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all dynamic schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;export-all-dynamic&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-static&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all static schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;pause-all-static&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all active schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;stop-all-active&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-inactive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all inactive schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;start-all-inactive&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-active-static&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all active static schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;stop-all-active-static&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-active-dynamic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all active dynamic schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;stop-all-active-dynamic&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-inactive-static&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all inactive static schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;start-all-inactive-static&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-all-inactive-dynamic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Operate a command on all inactive dynamic schedules.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;command&amp;quot;: &amp;quot;remove-all-inactive-dynamic&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;dynamic-demo-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#dynamic-demo-1&quot;&gt;Dynamic Demo 1&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For example, we need to build a flow that triggers on UK public holidays to stop recording the OEE (Overall Equipment Efficiency) or lock the entry gates of the factory. To achieve this, we can integrate a UK public holiday API into our Node-RED flow, fetch the holiday data, and then trigger actions based on those holidays.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Inject node onto the canvas and set it to trigger on deploy after &lt;code&gt;0.1&lt;/code&gt; seconds.&lt;/li&gt;
&lt;li&gt;Next, drag the HTTP request node onto the canvas, set the method to GET, and use the URL &lt;code&gt;https://www.gov.uk/bank-holidays.json&lt;/code&gt;. Set the return to &amp;quot;parsed JSON object&amp;quot;.&lt;/li&gt;
&lt;li&gt;Drag the Function node onto the canvas and add the following JavaScript code into it:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-926&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-926&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Retrieve public holidays for England and Wales from the API response&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; engHols &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;england-and-wales&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;events&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Clear out any existing schedules before adding new ones&lt;/span&gt;&lt;br /&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;remove-all&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create an array to hold the new holiday schedules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newSchedules &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Loop through all the holiday events&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; engHols&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; index&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hol &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; engHols&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Get the current holiday&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Convert the holiday date to a Date object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Skip holidays that are in the past (before the current date)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Skip to the next holiday&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create a new schedule for upcoming holidays&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newSchedule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Command to add a new schedule&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Holiday name with year&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;topic&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Holiday title as topic&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;expression&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Holiday date to use as an expression&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;expressionType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dates&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Define the type as dates&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hol&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Send the holiday details as the payload&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;payloadType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Specify that the payload is in JSON format&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Add the new schedule to the list of new schedules&lt;/span&gt;&lt;br /&gt;    newSchedules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newSchedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;    &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the topic as empty (not used for now)&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the payload to the new schedules array created above&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newSchedules&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Return the updated message with new schedules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-926&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag a cron-plus node onto the canvas. Connect the Inject node to the HTTP request node, the HTTP request node to the Function node, and the Function node to the cron-plus node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you can check the dynamic schedules list (see how at the end of this section).&lt;/p&gt;
&lt;div id=&quot;nr-flow-213&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow213 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;3608db0d1bd59aa5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update bank holidays&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;00 02 * * 1&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;252cb7c88de78e45&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;252cb7c88de78e45&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://www.gov.uk/bank-holidays.json&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cf71e6ad0a983d80&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cf71e6ad0a983d80&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;england bank holiday schedules&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const engHols = msg.payload[&#92;&#92;&#92;&quot;england-and-wales&#92;&#92;&#92;&quot;].events&#92;&#92;n&#92;&#92;n// clear out existing schedules&#92;&#92;nnode.send({topic:&#39;remove-all&#39;})&#92;&#92;n&#92;&#92;nconst newSchedules = []&#92;&#92;nfor(let index = 0; index &amp;lt; engHols.length; index++) {&#92;&#92;n    const hol = engHols[index];&#92;&#92;n    const date = new Date(hol.date)&#92;&#92;n    if (date.valueOf() &amp;lt; Date.now()) {&#92;&#92;n        continue&#92;&#92;n    }&#92;&#92;n    const newSchedule = {&#92;&#92;n        &#92;&#92;&#92;&quot;command&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;add&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: hol.title + ` (${date.getFullYear()})`,&#92;&#92;n        &#92;&#92;&#92;&quot;topic&#92;&#92;&#92;&quot;: hol.title,&#92;&#92;n        &#92;&#92;&#92;&quot;expression&#92;&#92;&#92;&quot;: hol.date,&#92;&#92;n        &#92;&#92;&#92;&quot;expressionType&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;dates&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;payload&#92;&#92;&#92;&quot;: hol,&#92;&#92;n        &#92;&#92;&#92;&quot;payloadType&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;json&#92;&#92;&#92;&quot;&#92;&#92;n    }&#92;&#92;n    newSchedules.push(newSchedule)    &#92;&#92;n}&#92;&#92;n&#92;&#92;nmsg.topic = &#39;&#39;&#92;&#92;nmsg.payload = newSchedules&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;abea360f336bbf5c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;abea360f336bbf5c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cronplus&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;outputField&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;timeZone&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;storeName&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;commandResponseMsgOutput&#92;&quot;:&#92;&quot;output2&#92;&quot;,&#92;&quot;defaultLocation&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;defaultLocationType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;options&#92;&quot;:[],&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dfff5dae3de9e7de&#92;&quot;],[&#92;&quot;7834e47a1631346f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5a53df2dedde1d2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;list-all&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;abea360f336bbf5c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7834e47a1631346f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;list&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dfff5dae3de9e7de&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;action&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;041f7306088daf24&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;1791a7bd576b3a15&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;remove-all&#92;&quot;,&#92;&quot;x&#92;&quot;:120,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;abea360f336bbf5c&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow213.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-213&#39;) })&lt;/script&gt;
&lt;h4 id=&quot;dynamic-demo-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#dynamic-demo-2&quot;&gt;Dynamic Demo 2&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Additionally, I&#39;d like to share another demo that Steve has prepared for the community, which demonstrates dynamic scheduling based on the best energy prices:&lt;/p&gt;
&lt;div id=&quot;nr-flow-214&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow214 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;0f969cd96da84b2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://api.awattar.at/v1/marketdata&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;32e08539d8339f74&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2a7465d67deae278&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;get liveData&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0f969cd96da84b2e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;32e08539d8339f74&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Billigsten 5 Stunden -&amp;gt; msg.liveData&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var timestamp = Date.now();&#92;&#92;nvar maxLoadingDuration = 5;&#92;&#92;n&#92;&#92;nvar cheapestHours = msg.payload.data&#92;&#92;n    .sort((a,b) =&amp;gt; a.marketprice - b.marketprice)&#92;&#92;n    .slice(0,maxLoadingDuration)&#92;&#92;n    .sort((a,b) =&amp;gt; a.start_timestamp - b.start_timestamp);&#92;&#92;n    var currentHour = cheapestHours.filter(d =&amp;gt; d.start_timestamp &amp;lt; timestamp&#92;&#92;n                                        &amp;amp;&amp;amp; d.end_timestamp &amp;gt; timestamp);&#92;&#92;nmsg.liveData = {&#92;&#92;n    soc:msg.payload,&#92;&#92;n    cheapestHours: cheapestHours&#92;&#92;n}&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5c56b3ca5ac4f7c2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;89c2acf51e7fbc9c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;merge active and new schedules&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;&#92;&#92;nconst inputData = msg.liveData.cheapestHours&#92;&#92;nconst activeSchedules = msg.activeSchedules || []&#92;&#92;n&#92;&#92;n// Clear existing schedules&#92;&#92;nnode.send({ topic: &#92;&#92;&#92;&quot;remove-all-dynamic&#92;&#92;&#92;&quot; });&#92;&#92;n&#92;&#92;n// helper function&#92;&#92;nconst makeSchedule = (start, time, suffix) =&amp;gt; {&#92;&#92;n    const isStart = start == true || start === &#92;&#92;&#92;&quot;start&#92;&#92;&#92;&quot; || start === &#92;&#92;&#92;&quot;on&#92;&#92;&#92;&quot; || start == 1&#92;&#92;n    const title = formatTime(time) + (isStart ? &#92;&#92;&#92;&quot;-on&#92;&#92;&#92;&quot; : &#92;&#92;&#92;&quot;-off&#92;&#92;&#92;&quot;)&#92;&#92;n    const name = suffix ? `${title} (${suffix}) ` : title&#92;&#92;n    return {&#92;&#92;n        &#92;&#92;&#92;&quot;command&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;add&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: name,&#92;&#92;n        &#92;&#92;&#92;&quot;expression&#92;&#92;&#92;&quot;: time,&#92;&#92;n        &#92;&#92;&#92;&quot;expressionType&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;dates&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;payloadType&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;str&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;payload&#92;&#92;&#92;&quot;: isStart ? &#92;&#92;&#92;&quot;start&#92;&#92;&#92;&quot; : &#92;&#92;&#92;&quot;stop&#92;&#92;&#92;&quot;,&#92;&#92;n    }&#92;&#92;n}&#92;&#92;n// helper function&#92;&#92;nconst formatTime = (date) =&amp;gt; {&#92;&#92;n    const d = new Date(date)&#92;&#92;n    const hh = (&#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot; + d.getHours()).padStart(2, &#92;&#92;&#92;&quot;0&#92;&#92;&#92;&quot;)&#92;&#92;n    const mm = (&#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot; + d.getMinutes()).padStart(2, &#92;&#92;&#92;&quot;0&#92;&#92;&#92;&quot;)&#92;&#92;n    return `${hh}:${mm}`&#92;&#92;n}&#92;&#92;n&#92;&#92;n// vars&#92;&#92;nconst newSchedules = []&#92;&#92;nconst mergedSchedules = []&#92;&#92;nconst keepSchedules = []&#92;&#92;n&#92;&#92;nfor (let index = 0; index &amp;lt; inputData.length; index++) {&#92;&#92;n    const element = inputData[index];&#92;&#92;n    let suffix = &#39;&#39;&#92;&#92;n    suffix = element.marketprice + &#92;&#92;&#92;&quot; &#92;&#92;&#92;&quot; + element.unit&#92;&#92;n    const startTime = new Date(element.start_timestamp)&#92;&#92;n    const endTime = new Date(element.end_timestamp)&#92;&#92;n    newSchedules.push(makeSchedule(&#92;&#92;&#92;&quot;start&#92;&#92;&#92;&quot;, startTime.valueOf(), suffix))&#92;&#92;n    newSchedules.push(makeSchedule(&#92;&#92;&#92;&quot;stop&#92;&#92;&#92;&quot;, endTime.valueOf(), suffix))&#92;&#92;n}&#92;&#92;n&#92;&#92;n&#92;&#92;n// if there are any existing schedules not yet operated&#92;&#92;n// and they are before the first in the new data, lets keep them&#92;&#92;nif (newSchedules?.length) {&#92;&#92;n    const firstNewSchedule = newSchedules[0]&#92;&#92;n    const existingSchedulesBeforeFirstNew = activeSchedules?.filter(e =&amp;gt; e.expression &amp;lt; firstNewSchedule.expression)&#92;&#92;n    if (existingSchedulesBeforeFirstNew?.length) {&#92;&#92;n        keepSchedules.push(...existingSchedulesBeforeFirstNew.map(e =&amp;gt; {&#92;&#92;n            const n = e.name&#92;&#92;n            const k = makeSchedule (e.payload, e.expression) &#92;&#92;n            k.name = n.replace(&#39; (keep)&#39;, &#39;&#39;) + &#92;&#92;&#92;&quot; (keep)&#92;&#92;&#92;&quot;&#92;&#92;n            return k&#92;&#92;n        }))&#92;&#92;n    }&#92;&#92;n} else {&#92;&#92;n    // keep all existing active schedules (as there are no new ones)&#92;&#92;n    keepSchedules.push(...activeSchedules)&#92;&#92;n}&#92;&#92;n&#92;&#92;nmergedSchedules.push(...newSchedules, ...keepSchedules)&#92;&#92;nmergedSchedules.sort((a, b) =&amp;gt; a.expression - b.expression) // order by expression asc&#92;&#92;n&#92;&#92;n// deduplicate the schedules by seeing if there are consecutive on/off schedules&#92;&#92;nlet deduplicatedSchedules = [];&#92;&#92;nlet prevSchedule&#92;&#92;nfor (let i = 0; i &amp;lt; mergedSchedules.length; i++) {&#92;&#92;n    const currentSchedule = mergedSchedules[i]&#92;&#92;n    if (i === 0) {&#92;&#92;n        deduplicatedSchedules.push(currentSchedule);&#92;&#92;n    } else {&#92;&#92;n        if (currentSchedule.payload === prevSchedule.payload) {&#92;&#92;n            // to scheules are the same (start/start or stop/stop)&#92;&#92;n            if (currentSchedule.payload === &#92;&#92;&#92;&quot;start&#92;&#92;&#92;&quot;) {&#92;&#92;n                // ignore this one as the previous one was a &#92;&#92;&#92;&quot;start&#92;&#92;&#92;&quot; (and due to sorting, this one is superfluous)&#92;&#92;n            } else if (currentSchedule.payload === &#92;&#92;&#92;&quot;stop&#92;&#92;&#92;&quot;) {&#92;&#92;n                // since the previous one was a &#92;&#92;&#92;&quot;stop&#92;&#92;&#92;&quot;, we need to update the previous schedule to the new stop time&#92;&#92;n                prevSchedule.expression = currentSchedule.expression&#92;&#92;n            }&#92;&#92;n        } else {&#92;&#92;n            deduplicatedSchedules.push(currentSchedule); // push the current schedule&#92;&#92;n        }&#92;&#92;n    }&#92;&#92;n    prevSchedule = currentSchedule&#92;&#92;n}&#92;&#92;n&#92;&#92;n// node.warn({newSchedules, keepSchedules, mergedSchedules, deduplicatedSchedules}) // debug&#92;&#92;nmsg.payload = deduplicatedSchedules&#92;&#92;nmsg.topic = &#92;&#92;&#92;&quot;update schedules&#92;&#92;&#92;&quot;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b6a5d42c7751fae2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;827e16c3f02d1962&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Clear all scedules&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;remove-all-dynamic&#92;&quot;,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b6a5d42c7751fae2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;32a88825fe3edf37&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;start&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;start&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1250,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e84ba501a1405907&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5e5497cff754ef73&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;stop&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1250,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b2e8c3606bd04897&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e84ba501a1405907&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;start something&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:true,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1460,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b2e8c3606bd04897&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;stop something&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:true,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1460,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b6a5d42c7751fae2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cronplus&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;outputField&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;timeZone&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;storeName&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;commandResponseMsgOutput&#92;&quot;:&#92;&quot;output2&#92;&quot;,&#92;&quot;defaultLocation&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;defaultLocationType&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;options&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1020,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;32a88825fe3edf37&#92;&quot;,&#92;&quot;5e5497cff754ef73&#92;&quot;],[&#92;&quot;fe51aaba903612eb&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5c56b3ca5ac4f7c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link call&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;ee57d78d1c769d1b&#92;&quot;],&#92;&quot;linkType&#92;&quot;:&#92;&quot;static&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;89c2acf51e7fbc9c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4cf44f6c7bd1461&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 4&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;29dcf0872d3f7ca4&#92;&quot;],&#92;&quot;x&#92;&quot;:505,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5c56b3ca5ac4f7c2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fe51aaba903612eb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 17&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;a1c12404f726b02f&#92;&quot;],&#92;&quot;x&#92;&quot;:1215,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;test data&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;6b39e36054edcc22&#92;&quot;,&#92;&quot;32388c4b0af7a5b1&#92;&quot;,&#92;&quot;73a529bfd3742503&#92;&quot;,&#92;&quot;43aa8690b4167bcc&#92;&quot;,&#92;&quot;dae8031ee5f37eb5&#92;&quot;,&#92;&quot;29dcf0872d3f7ca4&#92;&quot;],&#92;&quot;x&#92;&quot;:214,&#92;&quot;y&#92;&quot;:579,&#92;&quot;w&#92;&quot;:522,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b39e36054edcc22&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;32388c4b0af7a5b1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;32388c4b0af7a5b1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;cheapestHours sample&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;liveData&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;{&#92;&#92;n      &#92;&#92;&#92;&quot;soc&#92;&#92;&#92;&quot;: {},&#92;&#92;n      &#92;&#92;&#92;&quot;cheapestHours&#92;&#92;&#92;&quot;: [&#92;&#92;n        {&#92;&#92;n          &#92;&#92;&#92;&quot;start_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 07:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;end_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 12:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;marketprice&#92;&#92;&#92;&quot;: 66.02,&#92;&#92;n          &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Eur/MWh&#92;&#92;&#92;&quot;&#92;&#92;n        },&#92;&#92;n        {&#92;&#92;n          &#92;&#92;&#92;&quot;start_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 20:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;end_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 21:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;marketprice&#92;&#92;&#92;&quot;: 62.48,&#92;&#92;n          &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Eur/MWh&#92;&#92;&#92;&quot;&#92;&#92;n        }&#92;&#92;n      ]&#92;&#92;n    }&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dae8031ee5f37eb5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;73a529bfd3742503&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;43aa8690b4167bcc&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;43aa8690b4167bcc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;cheapestHours overlap&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;liveData&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;{&#92;&#92;n      &#92;&#92;&#92;&quot;soc&#92;&#92;&#92;&quot;: {},&#92;&#92;n      &#92;&#92;&#92;&quot;cheapestHours&#92;&#92;&#92;&quot;: [&#92;&#92;n        {&#92;&#92;n          &#92;&#92;&#92;&quot;start_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 08:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;end_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 11:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;marketprice&#92;&#92;&#92;&quot;: 66.02,&#92;&#92;n          &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Eur/MWh&#92;&#92;&#92;&quot;&#92;&#92;n        },&#92;&#92;n        {&#92;&#92;n          &#92;&#92;&#92;&quot;start_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 20:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;end_timestamp&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;2025-05-07 21:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n          &#92;&#92;&#92;&quot;marketprice&#92;&#92;&#92;&quot;: 62.48,&#92;&#92;n          &#92;&#92;&#92;&quot;unit&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Eur/MWh&#92;&#92;&#92;&quot;&#92;&#92;n        }&#92;&#92;n      ]&#92;&#92;n    }&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;dae8031ee5f37eb5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dae8031ee5f37eb5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;junction&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29dcf0872d3f7ca4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29dcf0872d3f7ca4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;51b3de02bcf463a3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 16&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;b4cf44f6c7bd1461&#92;&quot;],&#92;&quot;x&#92;&quot;:695,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Subroutine for getting active schedules&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;ee57d78d1c769d1b&#92;&quot;,&#92;&quot;9956e352b1728160&#92;&quot;,&#92;&quot;aba3e0f7de7c6f54&#92;&quot;,&#92;&quot;cc753a34602daf70&#92;&quot;,&#92;&quot;e4b0cb5dbf1fcbcc&#92;&quot;,&#92;&quot;a1c12404f726b02f&#92;&quot;],&#92;&quot;x&#92;&quot;:594,&#92;&quot;y&#92;&quot;:439,&#92;&quot;w&#92;&quot;:712,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;ee57d78d1c769d1b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;get-active-dynamic schedules&#92;&quot;,&#92;&quot;links&#92;&quot;:[],&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9956e352b1728160&#92;&quot;]],&#92;&quot;l&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;9956e352b1728160&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;export-active-dynamic&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:905,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b6a5d42c7751fae2&#92;&quot;]],&#92;&quot;l&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;aba3e0f7de7c6f54&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;move&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.result&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;activeSchedules&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1215,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cc753a34602daf70&#92;&quot;]],&#92;&quot;l&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;cc753a34602daf70&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link-return&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;return&#92;&quot;,&#92;&quot;links&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1265,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e4b0cb5dbf1fcbcc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;_linkSource&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;istype&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;array&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;array&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1165,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aba3e0f7de7c6f54&#92;&quot;]],&#92;&quot;l&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;a1c12404f726b02f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f559cf0eb4eca11c&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;f3ff5331698e1750&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 12&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;fe51aaba903612eb&#92;&quot;],&#92;&quot;x&#92;&quot;:1105,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e4b0cb5dbf1fcbcc&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow214.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-214&#39;) })&lt;/script&gt;
&lt;p&gt;If you need to see the dynamic schedules of a specific node, double-click on it and click on the &#39;Dynamic Schedules&#39; button from the configuration panel. This will show all of the dynamic schedules associated with that node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Dynamic Schedules&#39; button and the list of all dynamically scheduled events.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dynamic-schedules-list.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Dynamic Schedules&#39; button and the list of all dynamically scheduled events.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can see, creating flexible and dynamic cron schedules Node-RED can give you complete control over your automation tasks. Whether it&#39;s simple, recurring events, or complex, time-sensitive triggers, the combination of cron expressions and dynamic controls allows for smarter, more efficient workflows.&lt;/p&gt;
&lt;p&gt;Take some time to explore these features and experiment with your own schedules. The more you play around with them, the better you&#39;ll understand how to tailor your flows to meet your exact needs.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and happy automating! If you run into any questions or need assistance along the way, don’t hesitate to reach out. We’re here to help!&lt;/p&gt;
&lt;p&gt;If you’re using Node-RED in your production environment, it’s important to keep your instances organized, scalable, and secure. FlowFuse can help with that by making it easier to manage and maintain your Node-RED setup, while also supporting faster deployment, scaling, and improved security.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us&lt;/a&gt; now to learn more.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/designing-flexible-cron-schedules-in-flowfuse-with-node-red/#wrapping-up&quot;&gt;Wrapping Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Designing flexible and intelligent schedules is a key part of building robust automation with Node-RED. Whether you’re triggering actions based on time, solar events, or dynamic runtime conditions, the cron-plus node gives you a powerful set of tools to fine-tune when your flows should run.&lt;/p&gt;
&lt;p&gt;By combining these scheduling techniques with the management features of FlowFuse, you can confidently build and operate reliable automation systems at any scale.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/</id>
        <title>How to Embed Webpages on the FlowFuse Dashboard</title>
        <summary>Learn how to embed external content like maps, reports, and widgets onto your FlowFuse dashboard.</summary>
        <updated>2025-05-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;When you build a dashboard, sometimes you need more than just internal data. Maybe it’s a live map, a report hosted elsewhere, or another dashboard — whatever it is, having to switch tabs breaks the flow. FlowFuse lets you embed external content like web pages, dashboards, PDFs, and widgets right into your dashboard. This guide shows you how to do exactly that — step by step — so your team has everything they need, all in one place.&lt;/p&gt;
&lt;h2 id=&quot;why-embed-webpages-in-your-dashboard%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#why-embed-webpages-in-your-dashboard%3F&quot;&gt;Why Embed Webpages in Your Dashboard?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Embedding external content directly into your FlowFuse dashboard can make your life a lot easier. Here’s why it’s worth considering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streamline Your Workflow:&lt;/strong&gt; No more hopping between tabs or switching apps. Everything you need can be in one place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Save Time on Rework:&lt;/strong&gt; If you’ve already built a report, chart, or page somewhere else, just embed it into your dashboard. No need to start from scratch.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quick Decisions:&lt;/strong&gt; Having all your key data together helps you see what’s important at a glance and act faster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cut Down on Clicks:&lt;/strong&gt; The fewer actions needed to get to your information, the more time you can spend on actually getting things done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-embed-webpages-on-your-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#how-to-embed-webpages-on-your-flowfuse-dashboard&quot;&gt;How to Embed Webpages On your FlowFuse Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Embedding external content into your FlowFuse dashboard is straightforward and flexible. In this section, you&#39;ll learn two ways to do it: using a direct URL and using embed code. We’ll also cover common issues you might face and how to fix them. Lastly, you&#39;ll see how to embed one FlowFuse dashboard inside another, making it easier to centralize important views in one place.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin embedding webpages on FlowFuse Dashboard, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running FlowFuse Instance:&lt;/strong&gt; Make sure you have a FlowFuse instance set up and running. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Dashboard:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (also known as Node-RED Dashboard 2.0 in the community) installed and properly configured on your instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@flowfuse/node-red-dashboard-2-ui-iframe:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard-2-ui-iframe&quot;&gt;node-red-dashboard-2-ui-iframe&lt;/a&gt; installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;step-1%3A-obtain-the-url-or-embed-code-of-the-webpage-you-want-to-embed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#step-1%3A-obtain-the-url-or-embed-code-of-the-webpage-you-want-to-embed&quot;&gt;Step 1: Obtain the URL or Embed Code of the Webpage You Want to Embed&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first step is identifying and grabbing the URL of the webpage or external content you want to embed into your FlowFuse dashboard. This could be a live dashboard, report, Google Maps, video, or any other type of content.&lt;/p&gt;
&lt;p&gt;When embedding content from third-party sources, make sure the following conditions the page or content you&#39;re embedding should be publicly accessible or have the proper permissions for embedding. For example, private reports or webpages require login credentials or an API key, which should be handled securely.&lt;/p&gt;
&lt;p&gt;Some websites may restrict embedding through iframes due to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS&quot;&gt;Cross-Origin Resource Sharing (CORS)&lt;/a&gt; policies. Check whether the external site allows embedding if the content doesn’t load properly.&lt;/p&gt;
&lt;p&gt;Many platforms, such as YouTube and Google Maps, provide a specific &amp;quot;embed code or URL&amp;quot; that is more suitable for embedding. Ensure you use the correct embed link or code these platforms offer to guarantee smooth integration.&lt;/p&gt;
&lt;p&gt;Once the URL or embed code is ready, move on to the next step.&lt;/p&gt;
&lt;h4 id=&quot;step-2%3A-embedding-the-webpage-on-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#step-2%3A-embedding-the-webpage-on-flowfuse-dashboard&quot;&gt;Step 2: Embedding the Webpage on FlowFuse Dashboard&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now that you’ve gathered the URL or embed code for the external content you want to embed, it’s time to add it to your FlowFuse dashboard. Below are two methods for embedding external content:&lt;/p&gt;
&lt;h5 id=&quot;2.1-embed-via-url&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#2.1-embed-via-url&quot;&gt;2.1 Embed via URL&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;The easiest and most straightforward way to embed external content is by using the URL. FlowFuse&#39;s iframe node allows you to use an external URL directly. Here’s how to do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the ui_iframe widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the widget to open its configuration dialog.
&lt;ul&gt;
&lt;li&gt;Create a new group for it to render in.&lt;/li&gt;
&lt;li&gt;Set the size (width and height).&lt;/li&gt;
&lt;li&gt;Enter the URL you want to embed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;ui_iframe widget configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/if_frame-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;iframe widget configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click Done and then Deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a quick hands-on practice, you can try embedding a weather widget, Google Maps, Google Calendar, or a hosted PDF on your dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Weather widget embedded in FlowFuse Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/weather-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Weather widget embedded in FlowFuse Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Google Map embedded in FlowFuse Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/google-map.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Google Map embedded in FlowFuse Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;PDF embedded in FlowFuse Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pdf.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;PDF embedded in FlowFuse Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Google Calendar embedded in FlowFuse Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/google-calendar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Google Calendar embedded in FlowFuse Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h5 id=&quot;2.2-embed-via-html-embed-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#2.2-embed-via-html-embed-code&quot;&gt;2.2 Embed via HTML Embed Code&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;If you have an embed code from third-party services, you can use this code to embed the content into your FlowFuse dashboard. Here’s how to do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;ui-template&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it to open its configuration dialog.
&lt;ul&gt;
&lt;li&gt;Create a new group for it to render in.&lt;/li&gt;
&lt;li&gt;Set the size (width and height).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Paste your embed code into the template widget. Most embed codes include both HTML and JavaScript, so follow this structure:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-179&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-179&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Paste your HTML code here --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Paste your JavaScript code here&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-179&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Some services provide an &lt;strong&gt;iframe&lt;/strong&gt; tag. In this case, you need only copy the URL and use the embedding via the URL method.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and &lt;strong&gt;Deploy&lt;/strong&gt; to save your changes once you&#39;ve added the code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Animated weather widget on the Flowfuse dashboard, embedded with code.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/weather-widget.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Animated weather widget on the Flowfuse dashboard, embedded with code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that you’ve learned how to embed external content into your FlowFuse dashboard, one day you may need to embed your FlowFuse dashboard elsewhere—either on another FlowFuse dashboard or an external site. If you’ve tried and found that it’s not working as expected.&lt;/p&gt;
&lt;p&gt;This is a security feature designed to protect your data. FlowFuse dashboards, like many other web applications, implement security policies such as Cross-Origin Resource Sharing (CORS) and the X-Frame-Options header. These policies ensure that your dashboard is only viewed in trusted environments, preventing malicious sites from tampering with your data or exposing it to unauthorized users.&lt;/p&gt;
&lt;p&gt;However, if you need to embed your FlowFuse dashboard into other websites or on another FlowFuse dashboard, it’s possible to do so with some configuration changes. Below is a section on how to enable embedding securely of FlowFuse Dashboard:&lt;/p&gt;
&lt;h3 id=&quot;enabling-embedding-of-flowfuse-dashboards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#enabling-embedding-of-flowfuse-dashboards&quot;&gt;Enabling Embedding of FlowFuse Dashboards&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Go to your FlowFuse instance settings.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;editor&lt;/strong&gt; settings and enable &lt;strong&gt;&amp;quot;Allow Dashboard to be embedded in an iFrame&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse instance settings showing the option to allow dashboard embedding in an iframe.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/allow-dashboard-embedding.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse instance settings showing the option to allow dashboard embedding in an iframe.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Save Settings and restart&lt;/strong&gt; your instance for the changes to take effect.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse OEE Dashboard embedded in another FlowFuse dashboard.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/embedding-flowfuse-oee-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/a&gt;
&lt;em&gt;FlowFuse OEE Dashboard embedded in another FlowFuse dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse dashboards offer great flexibility, making it easy to embed external content like weather widgets, maps, and PDFs directly into your workspace. With a few simple steps, you can also embed FlowFuse dashboards into other websites, ensuring everything you need is in one place.&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in learning more about embedding webpages or enhancing your FlowFuse dashboards, check out the following blogs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/&quot;&gt;Mapping Location on Dashboard&lt;/a&gt;: In this article, we dive into how you can embed location maps into your FlowFuse dashboard. Learn how to map locations, track real-time data, and make your dashboards more interactive and informative.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2025/05/displaying-embeded-webpages-on-node-red-dashboard/#&quot;&gt;Generating PDF Reports with Node-RED and FlowFuse&lt;/a&gt;: This guide explains how to generate PDF reports directly with Node-RED and FlowFuse and how to preview these reports within your FlowFuse dashboards.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/</id>
        <title>FlowFuse 2.17: Easier remote instance onboarding, Dashboard blueprint, PDF generation, and more</title>
        <summary>Build a dashboard in one click, create PDF reports from your data, and import instances when installing Device Agent</summary>
        <updated>2025-05-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release is focused on improvements that help you get up and running with FlowFuse much more quickly. Our vision is that you can get started with FlowFuse and have a successful application up and running, from scratch, in hours, not days, weeks or months. This release gets us closer to that vision by focusing on improvements to the installation process for the Device Agent, and two new Blueprints.&lt;/p&gt;
&lt;h2 id=&quot;device-agent-onboarding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#device-agent-onboarding&quot;&gt;Device Agent onboarding&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you already had a Node-RED instance running on a device, it was a bit of a hassle to get it connected to FlowFuse as a remote instance. You had to install the Device Agent, find that it clashed with your existing instance, turn off that instance, run the Device Agent again, find that you can&#39;t import your existing instance...and so on, until finally getting copies of your flows and adding them to FlowFuse manually.&lt;/p&gt;
&lt;p&gt;Lots of friction. We heard you.&lt;/p&gt;
&lt;p&gt;Now, when you install the Device Agent, it will automatically scan for an existing Node-RED instance running locally and help you import its flows into FlowFuse.&lt;/p&gt;
&lt;p&gt;This streamlines the whole process, saving you valuable time and effort. It ensures you can manage the Node-RED flows running on your edge device as quickly as possible.&lt;/p&gt;
&lt;h2 id=&quot;blueprint%3A-getting-started-with-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#blueprint%3A-getting-started-with-dashboard&quot;&gt;Blueprint: Getting Started with Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Getting Started with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Getting Started with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the most popular features of Node-RED is Dashboard 2.0. And starting now, getting started with Dashboard is as simple as one click.&lt;/p&gt;
&lt;p&gt;Our new Getting Started with Dashboard Blueprint deploys to a new Node-RED instance in a single click and demonstrates several examples of how to use Dashboard. These include various ways of visualizing data, the data entry widget that allows direct entry to a table, and audit log creation.&lt;/p&gt;
&lt;p&gt;New Dashboard nodes are added on a regular basis, and we will keep in mind which ones users would like help using as we iterate on this Blueprint.&lt;/p&gt;
&lt;p&gt;To put this Blueprint to use, check out the Blueprint page for &lt;a href=&quot;https://flowfuse.com/blueprints/getting-started/dashboard/&quot;&gt;Getting Started with Dashboard.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;blueprint%3A-pdf-report-generator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#blueprint%3A-pdf-report-generator&quot;&gt;Blueprint: PDF Report Generator&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of PDF Report Generator&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pdf-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of PDF Report Generator&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Until now, creating a presentable report using data accessed in your Node-RED instance was a manual effort.&lt;/p&gt;
&lt;p&gt;This new Blueprint makes it very easy to create PDF reports from your data. Using SQLite nodes and connecting to your database, this Blueprint  enables drag-and-drop field selection.&lt;/p&gt;
&lt;p&gt;To get you started using this Blueprint, we&#39;ve included sample data that is generated automatically.&lt;/p&gt;
&lt;p&gt;Instructions for using this Blueprint, including how to map fields from your database to our preconfigured fields, &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/pdf-report-generator/&quot;&gt;check out the Blueprint page.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;where-are-we-headed%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#where-are-we-headed%3F&quot;&gt;Where are we headed?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are focused on making it as easy as possible to get started with Node-RED, to manage Node-RED instances, and start building applications quickly. Some improvements on the way include &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/5415&quot;&gt;pulling from a Git repo&lt;/a&gt; (we shipped Git push last release), including &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/5179&quot;&gt;Blueprints for self-hosted installations&lt;/a&gt;, and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/223&quot;&gt;better information about resource usage&lt;/a&gt;. We&#39;re also busy at work on a number of core Node-RED items for the forthcoming 4.1.0 release.&lt;/p&gt;
&lt;p&gt;With this work and more on the way, we are continuing to deliver our vision of FlowFuse being the best way to unlock your industrial data, integrate everything and optimize faster.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.17 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/flowfuse-release-2-17/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/</id>
        <title>Part 1: Building an Andon Task Manager with FlowFuse</title>
        <summary>Build a real-time Andon Task Manager with FlowFuse and Node-RED, covering key features, dashboard design, and data storage.</summary>
        <updated>2025-05-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In modern manufacturing and service environments, speed and transparency are critical for addressing issues as they arise. An Andon system helps achieve this by enabling frontline workers to signal problems in real time, triggering quick responses from support teams.&lt;/p&gt;
&lt;p&gt;However, many manufacturers struggle to find a solution that truly fits their needs. Some tools lack essential features, while others are overloaded with unnecessary ones that add complexity.&lt;/p&gt;
&lt;p&gt;This blog series introduces a practical approach to building a real-time Andon Task Manager using FlowFuse and Node-RED. In this first part, the focus is on understanding the concept of an Andon system and laying the foundation for the solution.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-andon-task-manager%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#what-is-the-andon-task-manager%3F&quot;&gt;What is the Andon Task Manager?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Andon Task Manager is a digital system designed to streamline real-time issue reporting, escalation, and resolution tracking. Inspired by the traditional Andon systems used in lean manufacturing, it brings these concepts into a modern, cloud-enabled environment.&lt;/p&gt;
&lt;p&gt;At its core, it’s a communication and response tool designed to improve transparency and speed on the factory floor or within service teams. Frontline workers can quickly raise issues—like equipment breakdowns, material shortages, or support needs—which are immediately sent to the right person or team. Once the issue is resolved, the responder updates the status so everyone stays informed and the task is properly closed.&lt;/p&gt;
&lt;h2 id=&quot;what-problem-it-solves%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#what-problem-it-solves%3F&quot;&gt;What Problem It Solves?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a typical manufacturing environment, multiple processes run simultaneously across large factory floors. Each area—or line—has specific machinery, workflows, and potential points of failure. When something goes wrong, quick and clear communication is essential. However, factories are often spread out, and support teams are divided across different departments (e.g., maintenance, quality control, safety, etc.).&lt;/p&gt;
&lt;p&gt;In many cases, workers rely on informal or manual systems—such as radio calls, phone messages, or shouting across the floor—to report issues. These methods are inefficient, error-prone, and often delay response times. The lack of a structured, real-time communication system leads to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delayed responses because support staff are unaware of new issues&lt;/li&gt;
&lt;li&gt;Lack of visibility into the status of reported issues
= No accountability for weather the issue is acknowledged/resolved or not&lt;/li&gt;
&lt;li&gt;Unstructured logging that makes follow-up or audits difficult&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Andon Task Manager solves this by acting as a centralized system where any frontline worker can quickly raise an issue. Once submitted, the request is instantly visible to the relevant department—without needing someone to manually assign it. This enables self-routing and real-time visibility, ensuring the right people take action quickly and efficiently, even when the requester and responder are in completely different parts of the factory.&lt;/p&gt;
&lt;h2 id=&quot;planning-the-andon-task-manager&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#planning-the-andon-task-manager&quot;&gt;Planning the Andon Task Manager&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At the core of the system is the concept of a request. Every request represents a task or issue raised by an operator. To ensure traceability and clarity, each request should include key details. This structured format makes it easier for departments to manage and resolve issues efficiently.&lt;/p&gt;
&lt;p&gt;Each request must include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;: A unique identifier for the request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;line&lt;/code&gt;: The line or machine where the issue was raised.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;department&lt;/code&gt;: The department responsible for resolving the issue.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;created&lt;/code&gt;: The timestamp when the request was created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acknowledged&lt;/code&gt;: Timestamp indicating when the request was acknowledged.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resolved&lt;/code&gt;: Timestamp indicating when the issue was resolved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;note&lt;/code&gt;: Text added by users for context or follow-up.
Only predefined values for line and department should be allowed. These values will be managed through admin settings to ensure consistency across the system.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;defining-key-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#defining-key-features&quot;&gt;Defining Key Features&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The system needs to support core operations that reflect how issues are reported and resolved in real-life factory environments. These features help ensure that tasks are handled efficiently and that everyone involved knows the current status.&lt;/p&gt;
&lt;p&gt;The essential features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Request creation: Users select the line and department, enter a note, and submit a request.&lt;/li&gt;
&lt;li&gt;Acknowledge requests: A responder can mark a request as acknowledged once they start working on it.&lt;/li&gt;
&lt;li&gt;Resolve requests: After resolving the issue, the responder marks it as resolved.&lt;/li&gt;
&lt;li&gt;View filtering: Requests can be filtered by line or department.&lt;/li&gt;
&lt;li&gt;Admin tools: Admins can add and manage the list of departments and lines.&lt;/li&gt;
&lt;li&gt;Status display: Requests display their current state — pending, acknowledged, or resolved.&lt;/li&gt;
&lt;li&gt;Alerts: Visual or sound alerts for unacknowledged requests after a time threshold.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these actions will be timestamped to provide a clear history of who did what and when.&lt;/p&gt;
&lt;h3 id=&quot;dashboard-visualization-%26-ui-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#dashboard-visualization-%26-ui-design&quot;&gt;Dashboard Visualization &amp;amp; UI Design&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next step after defining the core features is to design an intuitive and efficient dashboard for both frontline workers and admin users. A well-organized interface ensures quick interactions and smooth navigation, especially in settings where timely responses are crucial.&lt;/p&gt;
&lt;p&gt;The system will support two user roles: admins and regular users. Regular users will have access to features such as submitting requests, viewing requests by department or line, and managing tasks within their area (e.g., acknowledging and resolving requests). Admins will have additional capabilities, including creating and managing departments and lines, and accessing all request data.&lt;/p&gt;
&lt;p&gt;The regular user&#39;s view will be a single-page interface with dynamic content updates. Rather than traditional page navigation, content will update based on the user’s selection of a department or line. For example, when a user selects a production line, the request list and relevant controls will automatically update to display only the requests related to that line.&lt;/p&gt;
&lt;p&gt;The admin view will have a dedicated view, including a form for creating new lines or departments and a table displaying all requests. This view will also feature a menu for quickly switching between specific department or line section, improving system management efficiency.&lt;/p&gt;
&lt;p&gt;This design keeps the interface focused and responsive. It avoids unnecessary complexity while providing all necessary tools for users to perform their tasks efficiently — whether they are reporting an issue or managing overall operations.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-admin-veiw.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/line-menu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/line-page.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/department-menu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/department-wise.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The following dashboard image illustrates the intended design and key objectives of our Andon Task Manager.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;storage-mechanism&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#storage-mechanism&quot;&gt;Storage Mechanism&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To ensure a simple and efficient data management system for the Andon Task Manager, we will use SQLite to store user requests. SQLite is a lightweight, easy-to-manage database that is well-supported in Node-RED through the &lt;code&gt;node-red-contrib-sqlite node&lt;/code&gt;. This makes it an ideal choice for local deployments or scenarios where a lightweight database is needed.&lt;/p&gt;
&lt;p&gt;For dynamic runtime data—such as the user&#39;s selected line or department, as well as the full list of available lines and departments—FlowFuse’s built-in &lt;a href=&quot;https://flowfuse.com/docs/user/persistent-context/&quot;&gt;context storage&lt;/a&gt; will be utilized. This solution allows for fast access to real-time data while maintaining persistent state across sessions, without introducing unnecessary database complexity or overhead.&lt;/p&gt;
&lt;p&gt;By using both SQLite for structured request data and context storage for dynamic, session-based information, the system remains efficient and easy to maintain.&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/building-andon-task-manager-with-ff/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the next part of this series, we will focus on developing the Lines view for regular users, along with the navigation menu for switching between different line sections. Later, we will cover the development of the lines view and Admin interface.&lt;/p&gt;
&lt;p&gt;But if you can&#39;t wait to get started right away, don’t worry! You can &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;register&lt;/a&gt; for FlowFuse and get started with our ready-made &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/andon-system/&quot;&gt;Andon Task Manager blueprint&lt;/a&gt;, which is pre-configured for easy deployment. Stay tuned for the next installment to continue your journey toward building a comprehensive, real-time Andon Task Manager solution.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/</id>
        <title>How to Generate PDF Reports Using Node-RED in FlowFuse</title>
        <summary>Learn how to automate the generation of dynamic PDF reports within Node-RED and FlowFuse.</summary>
        <updated>2025-05-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Generating PDF reports is a common need in many workflows—whether you&#39;re logging data, sharing results, or creating summaries. With Node-RED and FlowFuse, you can easily automate turning your data into well-structured PDF files. This guide will show you how to set up step-by-step PDF report generation using simple tools and flows.
Generating reports allows you to capture snapshots of critical data, summarize system activities, and distribute insights in an easy-to-read and stored format. PDF is one of the most universally accepted formats for sharing documents, making it ideal for delivering structured information from your Node-RED flows.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you begin, make sure the following requirements are met:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have an active &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse account&lt;/a&gt; and a running FlowFuse instance.&lt;/li&gt;
&lt;li&gt;You are familiar with creating and deploying basic flows in Node-RED. If not, consider taking the &lt;a href=&quot;https://node-red-academy.learnworlds.com/course/node-red-getting-started&quot;&gt;Node-RED Fundamentals Course&lt;/a&gt; sponsored by FlowFuse.&lt;/li&gt;
&lt;li&gt;Ensure you have installed &lt;code&gt;flowfuse/node-red-dashboard&lt;/code&gt; &lt;code&gt;@flowfuse/node-red-dashboard-2-ui-iframe&lt;/code&gt; and &lt;code&gt;node-red-contrib-sqlite&lt;/code&gt; (The SQLite node is required for the demo data generation flow we provided. If you&#39;re not using that flow, you can skip this.).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setting-up-pdf-generation-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#setting-up-pdf-generation-in-node-red&quot;&gt;Setting Up PDF Generation in Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the prerequisites are in place, the next step is setting up your Node-RED environment to generate PDF reports. In this section, we will go over how to install the necessary Node-RED node and configure a flow to generate PDF reports.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-install-the-%40platmac%2Fnode-red-pdfbuilder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#step-1%3A-install-the-%40platmac%2Fnode-red-pdfbuilder&quot;&gt;Step 1: Install the @platmac/node-red-pdfbuilder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://flows.nodered.org/node/@platmac/node-red-pdfbuilder&quot;&gt;platmac/node-red-pdfbuilder&lt;/a&gt; node is the primary node for creating PDF reports in Node-RED. To install this node:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your Node-RED editor.&lt;/li&gt;
&lt;li&gt;Navigate to the &amp;quot;Manage palette&amp;quot; section from the top-right menu.&lt;/li&gt;
&lt;li&gt;Click on the &amp;quot;Install&amp;quot; tab and search for &lt;code&gt;@platmac/node-red-pdfbuilder&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot; to add the node to your palette.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This node allows you to dynamically generate PDFs from various inputs, which is exactly what you will need to generate reports.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t installed the &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;, &lt;code&gt;@flowfuse/node-red-dashboard-2-ui-iframe&lt;/code&gt; and &lt;code&gt;node-red-contrib-sqlite&lt;/code&gt; nodes, you can install them similarly.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-understanding-how-to-use-the-pdfbuilder-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#step-2%3A-understanding-how-to-use-the-pdfbuilder-node&quot;&gt;Step 2: Understanding How to Use the Pdfbuilder Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that the required node is installed, let&#39;s dive into how to use it and how to leverage the different attributes to customize your PDF reports. The pdfbuilder node in Node-RED simplifies generating PDFs by allowing you to define content, layout, and styling directly in your flow.&lt;/p&gt;
&lt;p&gt;The key advantage of using pdfbuilder node is that it operates server-side, meaning PDFs can be generated automatically without a browser or manual interaction. This makes it ideal for automated workflows where consistent, programmatically created documents are needed.&lt;/p&gt;
&lt;p&gt;When working with this node, you can use various attributes to customize the content and layout of the PDF, such as text, tables, images, page sizes, margins, headers, footers, and more. Below are the most commonly used attributes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Attribute&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the content of the PDF (text, tables, images, etc.).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;content&amp;quot;: &amp;quot;Hello, World!&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;style&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the style for content (font size, font family, etc.).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;style&amp;quot;: &amp;quot;headerStyle&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;layout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the layout of a table (e.g., &#39;lightHorizontalLines&#39;, &#39;noBorders&#39;).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;layout&amp;quot;: &amp;quot;lightHorizontalLines&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pageSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the page size for the PDF.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;pageSize&amp;quot;: &amp;quot;A4&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pageMargins&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the margins for the PDF (left, top, right, bottom).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;pageMargins&amp;quot;: [40, 60, 40, 60] }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;header&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies a header for the PDF. Can be a static text or dynamic content.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;header&amp;quot;: &amp;quot;My PDF Report&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;footer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies a footer for the PDF. Can be a static text or dynamic content.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;footer&amp;quot;: &amp;quot;Page {PAGE_NUM} of {PAGE_COUNT}&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defaultStyle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the default style for all content in the PDF.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;defaultStyle&amp;quot;: { &amp;quot;font&amp;quot;: &amp;quot;Helvetica&amp;quot;, &amp;quot;fontSize&amp;quot;: 12 } }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;background&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adds a background to the page or content area.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;background&amp;quot;: { &amp;quot;image&amp;quot;: &amp;quot;imageData&amp;quot; } }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;width&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the width of table cells or other elements.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;width&amp;quot;: 150 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;height&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the height of table cells or other elements.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;height&amp;quot;: 50 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alignment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the text alignment (left, center, right).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;alignment&amp;quot;: &amp;quot;center&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines the border for tables or table cells (style, width, and color).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ &amp;quot;border&amp;quot;: [true, true, true, true] }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For additional attributes and information, refer to the &lt;a href=&quot;https://pdfmake.github.io/docs/0.1/document-definition-object/&quot;&gt;pdfmake documentation&lt;/a&gt;, as pdfbuilder-node uses this library to generate PDFs.&lt;/p&gt;
&lt;p&gt;Here’s a simple example of how you can use these attributes to create a basic PDF:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-244&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-244&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;svg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;logoDataHere&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;alignment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Production Report - 2025&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Daily Production Summary with Operator Performance&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;subheader&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;alignment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;layout&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lightHorizontalLines&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;table&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;headerRows&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;widths&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Shift&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Units Produced&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Defective Units&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Operator&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Morning&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Afternoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;950&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;15&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jane Smith&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-02&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Morning&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1050&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;10&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;James Brown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-02&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Afternoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product C&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;800&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;30&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Emily Clark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-03&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Morning&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1100&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;25&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Michael Green&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-01-03&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Afternoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Product A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;980&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;18&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Sarah White&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;This table summarizes the daily production output across different shifts and operators. It includes total units produced and defective units recorded for quality analysis.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;fontSize&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;alignment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;justify&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Internal Use Only - Manufacturing Co.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;footer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;alignment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;styles&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;fontSize&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;bold&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;alignment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;subheader&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;fontSize&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;italics&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;grey&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;margin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;footer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;fontSize&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;grey&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;pageSize&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;pageMargins&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-244&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This example creates a simple PDF featuring a centered logo, a title, a subtitle, a table with a light horizontal line layout, a paragraph of text, and a footer at the end. The following screenshot shows how it looks. You can customize it by adjusting the styles, layout, and content.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example pdf result&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/example-pdf.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Example pdf result&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-creating-a-flow-to-generate-a-pdf&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#step-3%3A-creating-a-flow-to-generate-a-pdf&quot;&gt;Step 3: Creating a Flow to Generate a PDF&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s learn how to generate a PDF using dynamic inputs. For this, we’ll use the same example PDF report shown earlier—but this time, we’ll replace the hardcoded values with dynamic input data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For this guide&#39;s practical example, we will use the following SQLite flow that generates simulated production data. If you don&#39;t have the data source, you can import the flow below to follow along. After importing, deploy the flow and click the Inject node button to generate and insert the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When generating PDFs for your specific data, start by creating a flow to collect the information you want in the report. This data can come from sensors, databases, APIs, or even manual inputs.&lt;/p&gt;
&lt;div id=&quot;nr-flow-215&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow215 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;1e73fef718bb4876&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;5169b96ad66dcff6&#92;&quot;,&#92;&quot;b75fde37ea431d84&#92;&quot;,&#92;&quot;a571bbd7b0c0cb25&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:59,&#92;&quot;w&#92;&quot;:812,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;5169b96ad66dcff6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e73fef718bb4876&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Table&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:130,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b75fde37ea431d84&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b75fde37ea431d84&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e73fef718bb4876&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;fixed&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS production_report (&#92;&#92;n    id INTEGER PRIMARY KEY AUTOINCREMENT,&#92;&#92;n    date TEXT NOT NULL,&#92;&#92;n    shift TEXT NOT NULL,&#92;&#92;n    product TEXT NOT NULL,&#92;&#92;n    units_produced INTEGER NOT NULL,&#92;&#92;n    defective_units INTEGER NOT NULL,&#92;&#92;n    operator TEXT NOT NULL&#92;&#92;n);&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a571bbd7b0c0cb25&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a571bbd7b0c0cb25&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e73fef718bb4876&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlitedb&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;productiondata.sqlite&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;RWC&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;19ad08d3015ef8f2&#92;&quot;,&#92;&quot;b706e4aa8a2d0740&#92;&quot;,&#92;&quot;f32cdc1dd16b56b7&#92;&quot;,&#92;&quot;3708b00ae17defa5&#92;&quot;,&#92;&quot;c4464e3454a8805e&#92;&quot;,&#92;&quot;2df338e18c9a60d5&#92;&quot;],&#92;&quot;x&#92;&quot;:14,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:1332,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;19ad08d3015ef8f2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;prepared&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;INSERT INTO production_report (&#92;&#92;n    date,&#92;&#92;n    shift,&#92;&#92;n    product,&#92;&#92;n    units_produced,&#92;&#92;n    defective_units,&#92;&#92;n    operator&#92;&#92;n) VALUES (&#92;&#92;n    $date,&#92;&#92;n    $shift,&#92;&#92;n    $product,&#92;&#92;n    $units_produced,&#92;&#92;n    $defective_units,&#92;&#92;n    $operator&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1060,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2df338e18c9a60d5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b706e4aa8a2d0740&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Click to generate and insert data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f32cdc1dd16b56b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f32cdc1dd16b56b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Generate Simulated Production Data&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;const products = [&#92;&#92;&#92;&quot;Widget A&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Widget B&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Gadget X&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Component Z&#92;&#92;&#92;&quot;];&#92;&#92;nconst operators = [&#92;&#92;&#92;&quot;John Matthews&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Sarah Lee&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Amit Kumar&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Rita Patel&#92;&#92;&#92;&quot;];&#92;&#92;nconst shifts = [&#92;&#92;&#92;&quot;A&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;B&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;C&#92;&#92;&#92;&quot;];&#92;&#92;n&#92;&#92;nfunction getRandomInt(min, max) {&#92;&#92;n    return Math.floor(Math.random() * (max - min + 1)) + min;&#92;&#92;n}&#92;&#92;n&#92;&#92;nconst data = [];&#92;&#92;n&#92;&#92;nfor (let i = 0; i &amp;lt; 10; i++) {&#92;&#92;n    const date = new Date();&#92;&#92;n    date.setDate(date.getDate() - i); // Last 10 days&#92;&#92;n&#92;&#92;n    data.push({&#92;&#92;n        date: date.toISOString().split(&#39;T&#39;)[0],&#92;&#92;n        shift: shifts[getRandomInt(0, shifts.length - 1)],&#92;&#92;n        product: products[getRandomInt(0, products.length - 1)],&#92;&#92;n        units_produced: getRandomInt(400, 600),&#92;&#92;n        defective_units: getRandomInt(0, 10),&#92;&#92;n        operator: operators[getRandomInt(0, operators.length - 1)]&#92;&#92;n    });&#92;&#92;n}&#92;&#92;n&#92;&#92;nmsg.payload = data;&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3708b00ae17defa5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3708b00ae17defa5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c4464e3454a8805e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4464e3454a8805e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$date&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.date&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$shift&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.shift&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$product&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.product&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$units_produced&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.units_produced&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$defective_units&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.defective_units&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;params.$operator&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.operator&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;19ad08d3015ef8f2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2df338e18c9a60d5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b37428694e90b2c5&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ccca7810c6b3db41&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow215.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-215&#39;) })&lt;/script&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;SQLite&lt;/strong&gt; node and connect it to the Inject node. Configure the &lt;strong&gt;SQLite&lt;/strong&gt; node with the same database to generate the simulated data. Set the SQL Query type to &amp;quot;fixed statement&amp;quot; and use the following query:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-280&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-280&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; production_report&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-280&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Function&lt;/strong&gt; node onto the canvas and paste the following JavaScript code. When generating PDFs for your specific data, make sure to adjust the code to match your data structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-288&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-288&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Initialize table body with headers&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tableBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Date&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Shift&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Product&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Units Produced&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Defective Units&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Operator&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;replace-this-your-logo-svg&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Loop through data rows from SQLite (msg.payload)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    tableBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shift&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units_produced&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defective_units&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;operator&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; docDefinition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; logo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Adjust the logo size as needed&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;alignment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;center&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Header&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Production Report - 2025&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;header&#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Subheader&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Daily Production Summary with Operator Performance&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;subheader&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;alignment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;center&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Table&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lightHorizontalLines&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;headerRows&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;widths&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;*&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;auto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;*&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tableBody&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Description&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;This table summarizes the daily production output across different shifts and operators. It includes total units produced and defective units recorded for quality analysis.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;fontSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;alignment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;justify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Footer&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Internal Use Only - Manufacturing Co.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;footer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;alignment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;center&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;styles&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;fontSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;bold&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;alignment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;center&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;subheader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;fontSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;italics&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;grey&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;fontSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;grey&#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;pageSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;A4&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;pageMargins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; docDefinition&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-288&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;pdfbuilder&lt;/strong&gt; node onto the canvas. Set the input property to &lt;code&gt;msg.payload&lt;/code&gt;, set output type to Buffer, and output property to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;Write File&lt;/strong&gt; node, configure it with:
&lt;ul&gt;
&lt;li&gt;Filename: test.pdf&lt;/li&gt;
&lt;li&gt;Action: Overwrite file&lt;/li&gt;
&lt;li&gt;Add newline (&#92;n) to each payload?: Checked&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;SQLite&lt;/strong&gt; node to the &lt;strong&gt;Function&lt;/strong&gt; node, then to the &lt;strong&gt;pdfbuilder&lt;/strong&gt; node, and finally to the &lt;strong&gt;Write File&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the flow and click inject node to generate the pdf.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the PDF is generated, you can find it in the &lt;code&gt;.node-red&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;However, if you want to share the PDF with others, display it on the dashboard, and provide a download button, you can use the HTTP API, an iframe, and a few supporting nodes. Let&#39;s walk through how to do that next.&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-serving-the-pdf-via-http-and-previewing-it-on-the-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#step-4%3A-serving-the-pdf-via-http-and-previewing-it-on-the-dashboard&quot;&gt;Step 4: Serving the PDF via HTTP and Previewing It on the Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this step, we’ll make the generated PDF accessible through a web interface. You’ll be able to preview the PDF directly in the browser and embed it in your FlowFuse dashboard for a smooth, integrated experience. We’ll also add a download button so users can easily save the report. Instead of manually retrieving the file, we’ll create an HTTP endpoint to serve the PDF and use an iframe to display it.&lt;/p&gt;
&lt;h4 id=&quot;exposing-the-pdf-via-http&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#exposing-the-pdf-via-http&quot;&gt;Exposing the PDF via HTTP&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;http-in&lt;/strong&gt; node onto the canvas. Set the method to &#39;GET&#39; and the URL to &lt;code&gt;/report.pdf&lt;/code&gt;. This will create an HTTP endpoint for retrieving the generated PDF.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;http-in&lt;/strong&gt; node to the &lt;strong&gt;SQLite&lt;/strong&gt; node. This ensures that when a request is made to this endpoint, the necessary data is fetched from the database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After the &lt;strong&gt;Write File&lt;/strong&gt; node in your flow, add a &lt;strong&gt;Change&lt;/strong&gt; node. Connect it to the &lt;strong&gt;Write File&lt;/strong&gt; node, and configure it to set the following headers for the HTTP response:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.headers&lt;/code&gt; to:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-365&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-365&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;   &lt;br /&gt;   &#39;Content-Type&#39;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &#39;application/pdf&#39;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;br /&gt;   &#39;Content-Disposition&#39;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &#39;inline; filename=&lt;span class=&quot;token string&quot;&gt;&quot;report.pdf&quot;&lt;/span&gt;&#39; &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-365&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;HTTP-response&lt;/strong&gt; node onto the canvas and connect it to the Change node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the flow&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, this will send the generated PDF as a response to the incoming HTTP request, allowing it to be previewed in the browser. You can check by entering the URL:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/report.pdf&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;embedding-the-pdf-on-the-dashboard-and-adding-the-download-button&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#embedding-the-pdf-on-the-dashboard-and-adding-the-download-button&quot;&gt;Embedding the PDF on the Dashboard and Adding the Download Button&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&#39;s embed the PDF into the dashboard:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;ui-event&lt;/strong&gt; node onto the canvas and configure it with the appropriate UI base settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, drag an &lt;strong&gt;iframe&lt;/strong&gt; node onto the canvas.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select the correct group where the PDF should be displayed.&lt;/li&gt;
&lt;li&gt;Adjust the size according to your preferences.&lt;/li&gt;
&lt;li&gt;In the URL field, enter:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/report.pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Done and Deploy the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, when you open the dashboard, the generated PDF will be embedded and displayed directly on the dashboard page.&lt;/p&gt;
&lt;p&gt;Now, let&#39;s add a download button:&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-template&lt;/strong&gt; widget onto the canvas and paste the following HTML code into it:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-438&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-438&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://&amp;lt;your-instance-name&gt;.flowfuse.cloud/report.pdf&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;report.pdf&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #4f7a28&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 14px 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 4px 8px &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; background-color 0.3s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        Download Report&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-438&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dashboard displaying embedded PDF with a download button&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-with-embedded-report.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;[Dashboard displaying embedded PDF with a download button]&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-thought&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/05/how-to-generate-pdf-reports-using-node-red/#final-thought&quot;&gt;Final thought&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Automating PDF report generation in Node-RED is a great way to save time and effort. Using tools like the node-red-contrib-pdfmake node, you can quickly turn your data into well-designed PDFs without manual work. If you want to save time and avoid the setup process, you can directly use our ready-made &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/pdf-report-generator/&quot;&gt;PDF generation blueprint&lt;/a&gt;. It’s an easy way to get started and generate professional reports quickly.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/</id>
        <title>Part 3: Building an OEE Dashboard with FlowFuse</title>
        <summary>Build a responsive OEE dashboard with real-time updates using FlowFuse.</summary>
        <updated>2025-04-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/&quot;&gt;Part 2&lt;/a&gt;, we built the flow to calculate OEE for the production line using simulated production and downtime data and created a dashboard interface for visualization. However, we did not focus much on theme, layout, or styling.&lt;/p&gt;
&lt;p&gt;In Part 3, we will focus on improving the theme and design of the OEE dashboard. We will learn how to connect a real data source, adjust fields if your data structure differs, scale the dashboard for multiple production lines, and finally, explore how you can use it to take action based on insights.&lt;/p&gt;
&lt;p&gt;Let&#39;s get started!&lt;/p&gt;
&lt;h2 id=&quot;enhancing-the-dashboard-theme-and-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#enhancing-the-dashboard-theme-and-design&quot;&gt;Enhancing the Dashboard Theme and Design&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the planning section of &lt;a href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/&quot;&gt;Part 1&lt;/a&gt;, we introduced a mockup of the dashboard with a modern dark theme. The theme was built around a sleek, professional aesthetic, using high-contrast colors for readability and a visually appealing layout.&lt;/p&gt;
&lt;p&gt;The primary colors in the theme include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Black (#000000)&lt;/strong&gt; — used for the page background to create contrast and reduce eye strain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Charcoal Blue (#1A1C24)&lt;/strong&gt; — a deep, muted tone that adds depth while maintaining a clean and modern look, used for the groups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;White (#FFFFFF)&lt;/strong&gt; — used for text elements to ensure maximum readability against the dark background.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accent Colors&lt;/strong&gt; — vibrant colors such as teal, orange, green, yellow, and blue are used across widget elements, including chart bars, line graphs, and indicators. These accents help differentiate data types and bring attention to key metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But how do you come up with a dashboard design like this on your own? It starts with understanding why the theme matters. The design should reflect the context it is used in, the people interacting with it, and the mood it should convey. A dashboard on a factory floor may need to feel bold and focused, while one used by executives might aim for minimal and polished. A hospital system would need a tone that is calm, clean, and highly legible.&lt;/p&gt;
&lt;p&gt;If you have a brand palette, that’s a great starting point. If not, choose colors that support the usability and tone of your dashboard. Our OEE dashboard, for instance, was designed for manufacturing teams who need to quickly read live data. The layout needed to be sharp, high-contrast, and low on visual noise—ideal for control rooms with limited lighting. The dark theme helps key data stand out while reducing eye strain over long periods of use.&lt;/p&gt;
&lt;h3 id=&quot;modifying-theme&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#modifying-theme&quot;&gt;Modifying Theme&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open the Dashboard 2.0 sidebar from the Node-RED editor.&lt;/li&gt;
&lt;li&gt;Switch to the Theme tab.&lt;/li&gt;
&lt;li&gt;In the list of themes (you will likely see only the default one), click the settings (gear) icon next to it.&lt;/li&gt;
&lt;li&gt;In the theme settings, click any colored rectangle to open the color picker. You can use the wheel or the dropper tool at the bottom to pick exact colors:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Color tool for selecting colors for the theme&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/color-picking.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Color tool for selecting colors for the theme&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set Charcoal Blue (#1A1C24) as the color for the header background, group background, and group outline.&lt;/li&gt;
&lt;li&gt;Set Black (#000000) as the page background.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Update&lt;/strong&gt; and &lt;strong&gt;Deploy Changes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your dashboard should display the updated dark theme with a clean, modern appearance and improved visual contrast.&lt;/p&gt;
&lt;p&gt;However, additional adjustments are needed to fully align the visuals, specifically the chart grid lines and label text colors.&lt;/p&gt;
&lt;h3 id=&quot;to-update-these%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#to-update-these%3A&quot;&gt;To update these:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Double-click on a chart widget to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Scroll to the bottom of the chart config UI.&lt;/li&gt;
&lt;li&gt;Uncheck the following options:
&lt;ul&gt;
&lt;li&gt;Use ChartJs Default Text Colors&lt;/li&gt;
&lt;li&gt;Use ChartJs Default Grid Colors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set the text color to &lt;code&gt;#FFFFFF&lt;/code&gt; (white) and the grid line color to &lt;code&gt;#606060&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;, then &lt;strong&gt;Deploy the changes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These tweaks will ensure the charts match the dark theme and maintain good readability.&lt;/p&gt;
&lt;h2 id=&quot;improving-layout-consistency-across-screen-sizes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#improving-layout-consistency-across-screen-sizes&quot;&gt;Improving Layout Consistency Across Screen Sizes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you open the same dashboard on different screen sizes—such as a mobile phone, tablet, or smaller desktop monitor—you might find the layout inconsistent or cramped. For example, widgets may overlap or appear too small.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard broken layout on smaller screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-breaked-layout.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard broken layout on smaller screen&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;to-make-the-dashboard-truly-responsive%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#to-make-the-dashboard-truly-responsive%3A&quot;&gt;To make the dashboard truly responsive:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Page Settings&lt;/strong&gt; in the Node-RED Dashboard editor.&lt;/li&gt;
&lt;li&gt;Scroll down to locate the &lt;strong&gt;Breakpoint Settings Table&lt;/strong&gt; for different device sizes.&lt;/li&gt;
&lt;li&gt;Identify the &lt;strong&gt;Tablet&lt;/strong&gt; row in the table.&lt;/li&gt;
&lt;li&gt;Notice that the current Tablet column count is set to &lt;code&gt;9&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our OEE dashboard has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Four KPI widgets (OEE, Performance, Availability, Quality), each set to 3 columns wide.&lt;/li&gt;
&lt;li&gt;A total of 3 × 4 = 12 columns, which does not fit in the 9-column grid—so the layout breaks, and one widget drops to the next row.&lt;/li&gt;
&lt;li&gt;Other widgets like Production Summary and Downtime Events are each 6 columns wide, which leaves 3 columns of unused space in a 9-column layout.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;To correct this, set the Tablet column count to &lt;code&gt;6&lt;/code&gt; in the breakpoint table.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This change ensures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two KPI widgets fit perfectly per row (3 + 3 = 6).&lt;/li&gt;
&lt;li&gt;Summary widgets span the full row (6/6), making the layout cleaner and more consistent on tablet devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click Deploy the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Even after adjusting the breakpoint settings, one more issue may appear: inconsistent heights between the &lt;em&gt;Top Underperforming Machines&lt;/em&gt; and &lt;em&gt;Recent Downtime Events&lt;/em&gt; sections—especially when one of the tables has fewer rows than the other.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Inconsistent height of the widgets on OEE Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/table-incosistency.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Inconsistent height of the widgets on the OEE Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This can make the dashboard layout uneven, with one card appearing much shorter.&lt;/p&gt;
&lt;p&gt;To fix this visual imbalance, apply custom CSS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Template&lt;/strong&gt; widget onto your canvas.&lt;/li&gt;
&lt;li&gt;Set its type to &lt;code&gt;CSS (all pages)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the following CSS into the template:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-256&quot;&gt;
  &lt;pre class=&quot;language-css&quot;&gt;&lt;code id=&quot;code-256&quot; class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.nrdb-ui-group &gt; .v-card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100% &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-256&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Deploy the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;adding-header-elements%3A-logo-and-dashboard-title&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#adding-header-elements%3A-logo-and-dashboard-title&quot;&gt;Adding Header Elements: Logo and Dashboard Title&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To give your OEE Dashboard a professional look, add branding elements such as a company logo and a clear dashboard title. These additions improve usability and help users instantly recognize the dashboard&#39;s purpose.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag &lt;strong&gt;Template&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double click on it and add the following Vue code to it:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-282&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-282&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Teleport the title and logo to the #app-bar-actions area --&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Teleport&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#app-bar-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h3&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin-right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;OEE Dashboard&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Teleport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Teleport&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#app-bar-actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;&lt;br /&gt;               &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;               &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://flowfuse.com/handbook/images/logos/ff-logo--wordmark--white.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;               &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;margin-right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 25px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Teleport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;           &lt;span class=&quot;token literal-property property&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mounted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-282&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Update the &lt;code&gt;src&lt;/code&gt; attribute in the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag to your logo&#39;s path. If you are using FlowFuse, you can host your logo using the static assets service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click Deploy the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We are using Vue’s Teleport feature to insert a custom dashboard title and logo into the top bar of the Dashboard 2.0 layout. For more information, please read our article: &lt;a href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/&quot;&gt;Customise theming in your FlowFuse Dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The dashboard now looks clean, adapts well to all screen sizes, and maintains visual consistency across different UI elements. The header elements have also been enhanced to align with the overall design.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard with proper styling, theme&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-with-proper-styling.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard with proper styling, theme&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard with proper styling, theme&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-with-styling-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard with proper styling, theme&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard with proper styling, theme on smaller screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-tablet.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard with proper styling, theme on smaller screen&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard with proper styling, theme on smaller screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-tablet.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard with proper styling, theme on smaller screen&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;scaling-the-dashboard-for-multiple-production-lines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#scaling-the-dashboard-for-multiple-production-lines&quot;&gt;Scaling the Dashboard for Multiple Production Lines&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently, the dashboard is configured for a single production line. To support multiple lines, you must adjust your flows and dashboard structure to handle each line separately while keeping a consistent layout and theme.&lt;/p&gt;
&lt;h3 id=&quot;follow-these-steps%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#follow-these-steps%3A&quot;&gt;Follow these steps:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Select the dashboard flow that handles your current production line. Include all relevant change nodes that set values like &lt;code&gt;msg.quality&lt;/code&gt;, &lt;code&gt;msg.performance&lt;/code&gt;, etc., to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From the main menu, hover over &lt;strong&gt;Subflows&lt;/strong&gt; and click &lt;strong&gt;Create Subflow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Inside the subflow:
&lt;ul&gt;
&lt;li&gt;Add an &lt;strong&gt;Input&lt;/strong&gt; node, and connect it to all the change nodes you included from the original flow.&lt;/li&gt;
&lt;li&gt;Reconnect any &lt;strong&gt;Link In&lt;/strong&gt; node (that was previously wired to the change nodes) to the input of the newly created subflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;subflow properties&lt;/strong&gt;, and define environment variables to represent widget groups. In the dashboard widgets inside the subflow, reference these variables instead of hardcoding group names.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to apply the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This modular approach simplifies scaling and reduces manual work when adding new production lines to the dashboard.&lt;/p&gt;
&lt;h3 id=&quot;to-reuse-it-for-another-production-line%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#to-reuse-it-for-another-production-line%3A&quot;&gt;To reuse it for another production line:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Copy the entire OEE dashboard flow.&lt;/li&gt;
&lt;li&gt;Create a new tab.&lt;/li&gt;
&lt;li&gt;Paste the copied flow into the new tab.&lt;/li&gt;
&lt;li&gt;Rename the tab to match the new production line.&lt;/li&gt;
&lt;li&gt;Create a new dashboard page with the same configuration but a different name and path.&lt;/li&gt;
&lt;li&gt;Open the subflow by double-clicking on it and add a new group for dashboard widgets.&lt;/li&gt;
&lt;li&gt;Go to the configuration flow, and update the line&#39;s name to match the new production line.&lt;/li&gt;
&lt;li&gt;Adjust both shift duration values to reflect the new line’s schedule.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, you will have a separate page ready for your new production line. You can create as many pages as needed to monitor multiple production lines.&lt;/p&gt;
&lt;h2 id=&quot;connecting-your-real-data-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#connecting-your-real-data-source&quot;&gt;Connecting Your Real Data Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you have built a complete OEE dashboard using simulated factory data and learned how to reuse it for all your production lines, the next step is to connect it to your real factory environment.&lt;/p&gt;
&lt;p&gt;To make the dashboard truly useful in a live setting, you must understand how to integrate it with your data sources. Most commonly, the OEE dashboard relies on static or retained data, such as values stored in a database. First, determine whether your factory uses a relational database like MySQL or PostgreSQL, a NoSQL database like MongoDB, or a time-series database like InfluxDB.&lt;/p&gt;
&lt;h3 id=&quot;then%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#then%3A&quot;&gt;Then:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Use the &lt;strong&gt;Palette Manager&lt;/strong&gt; in Node-RED to install the corresponding contrib node for your selected database.&lt;/li&gt;
&lt;li&gt;Replace the existing &lt;code&gt;sqlite&lt;/code&gt; nodes in your flow with the nodes for the database you are using.&lt;/li&gt;
&lt;li&gt;If using SQL based database, queries may remain unchanged. For NoSQL or time-series DBs, rewrite the queries as needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For help, refer to our &lt;a href=&quot;https://flowfuse.com/node-red/database/&quot;&gt;Database&lt;/a&gt; section, which includes guides for MongoDB, PostgreSQL, InfluxDB, TimescaleDB, and DynamoDB.&lt;/p&gt;
&lt;p&gt;When connecting to your real data source, you may notice that the field names used in your database differ from those used in the our oee dashboard sqlite node queries. While this seems like a lot of manual work, the dashboard is designed with flexibility in mind. You only need to make two changes to adapt the queries to your schema.&lt;/p&gt;
&lt;h3 id=&quot;to-match-your-schema%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#to-match-your-schema%3A&quot;&gt;To match your schema:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open each database node and update the query to reflect your field names.
&lt;ul&gt;
&lt;li&gt;Do &lt;strong&gt;not&lt;/strong&gt; change the alias names — they are used throughout the dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Replace table names with those used in your actual database.&lt;/li&gt;
&lt;li&gt;Do &lt;strong&gt;not&lt;/strong&gt; change the dynamic parameters like &lt;code&gt;$startTime&lt;/code&gt;, &lt;code&gt;$endTime&lt;/code&gt;, and &lt;code&gt;$line&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example query:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-482&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-482&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   machine_name &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   area &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   line &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   total_produced_units &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   good_units &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; good_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   defect_units &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; defect_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   target_output &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; target_output&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; ProductionData&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $startTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $endTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-482&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Suppose your database uses different field names, such as time instead of timestamp, machine instead of machine_name, section instead of area, production_line instead of line, produced_units instead of total_produced_units, quality_units instead of good_units, faulty_units instead of defect_units, or planned_output instead of target_output. In that case, you should update the query accordingly. After modification, it should look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-486&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-486&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    machine &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    section &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    production_line &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    produced_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    quality_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; good_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    faulty_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; defect_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    planned_output &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; target_output&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; YourTableName &lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $startTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $endTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; production_line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-486&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;how-to-use-your-oee-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#how-to-use-your-oee-dashboard&quot;&gt;How to Use Your OEE Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your OEE dashboard is live. It updates in real-time and shows key metrics. But what should you do with the information?&lt;/p&gt;
&lt;p&gt;The dashboard is not just for display—it is there to help you take action. When OEE drops, do not stop at the number. Dig into the cause by checking the three main metrics: availability, performance, and quality.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If availability is low, check for unplanned stops, long changeovers, or idle machines.&lt;/li&gt;
&lt;li&gt;If performance is down, the line may run slower than expected.&lt;/li&gt;
&lt;li&gt;If quality has dropped, you may produce more rejects or rework.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Say your OEE drops from 82% to 65%, and performance is the problem. Start by checking how many good parts were produced. Look at reject counts—more bad parts affect both quality and output. Then, check downtime logs and machine performance. One or two machines are often behind the drop—maybe they had repeated issues or ran slowly after a setup.&lt;/p&gt;
&lt;p&gt;Use the 30-day trend graph to spot patterns over time. A sudden drop might show a specific issue, while a slow decline could signal a more significant process problem. Trends can also help you confirm if recent changes are making a real difference.
Finally, share what you find. Use the dashboard during team reviews or shift handovers to keep everyone focused on what needs fixing. An OEE dashboard&#39;s real value is how you respond to it.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-3/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This final part completes our series on building a real-time OEE dashboard with FlowFuse. You now have a fully functional, visually refined, and scalable dashboard that connects to live production data, adapts to multiple lines, and reflects your plant’s branding and layout requirements.&lt;/p&gt;
&lt;p&gt;By the end of this journey, you have built a dashboard and created a foundation for continuous improvement in your manufacturing environment using open-source, low-code tools.
We hope this series helped you understand how FlowFuse and Node-RED can quickly prototype and deploy powerful industrial applications. Thank you for following along!&lt;/p&gt;
&lt;p&gt;Suppose you have not built your OEE dashboard yet or are facing issues. In that case, you can get started instantly—&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up&lt;/a&gt; now and use our ready-made &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;OEE Dashboard Blueprint&lt;/a&gt; to accelerate your deployment.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/</id>
        <title>FlowFuse 2.16: Git Integration, improved log retention and more</title>
        <summary>Start pushing your snapshots to git, get alerted when resources are running low and more logging from Node-RED</summary>
        <updated>2025-04-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Another release from the FlowFuse team to keep &lt;a href=&quot;https://flowfuse.com/handbook/company/strategy/&quot;&gt;realising our mission&lt;/a&gt; to empower you to fuse the digital realm and physical reality.&lt;/p&gt;
&lt;h2 id=&quot;git-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#git-integration&quot;&gt;Git Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of a Git Pipeline Stage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/git-pipeline-stage.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of a Git Pipeline Stage&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This has been one of those features that has come up a number of times with our users; we knew we wanted to have Git integration in the platform, but we also wanted it to fit in a natural way with the developer workflows we provide.&lt;/p&gt;
&lt;p&gt;With this release, you can now add a Git Repository stage to your deployment pipelines. When the pipeline is triggered, the latest snapshot will get pushed to the configured repository.&lt;/p&gt;
&lt;p&gt;This is very much a &amp;quot;first-iteration&amp;quot; of the feature that will allow us to get feedback early and continue to iterate.&lt;/p&gt;
&lt;p&gt;With this release, the following restrictions apply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only GitHub.com hosted repostories are supported&lt;/li&gt;
&lt;li&gt;Users must create a GitHub Personal Access Token and add to their Team Settings&lt;/li&gt;
&lt;li&gt;We currently only support pushing snapshots to a Git repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This last point is important; this release lets you backup your flows to git, but we haven&#39;t yet enabled the return journey of pulling a snapshot from a Git repository back to your Node-RED instance. That&#39;ll come in the near future and will unlock a full git-based review workflow within the pipelines.&lt;/p&gt;
&lt;p&gt;We&#39;ll also look at enabling other Git hosting providers - let us know which you&#39;d like to see on the list.&lt;/p&gt;
&lt;p&gt;This feature is available to Enterprise teams on FlowFuse Cloud and self-hosted customers.&lt;/p&gt;
&lt;h2 id=&quot;better-node-red-log-handling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#better-node-red-log-handling&quot;&gt;Better Node-RED log handling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve improved the log handling within our Hosted Node-RED instances. Previously we were using a fix sized buffer in memory; meaning the noisier your Node-RED instance was, the less history you&#39;d have. The UI for browsing the logs was also awkward when you wanted to jump back to an earlier section of the logs.&lt;/p&gt;
&lt;p&gt;With this release, once you update your instances to the latest version, we will
now store the last 7 days worth of logs for each hosted Node-RED instance.&lt;/p&gt;
&lt;p&gt;To go along side this, we&#39;ve added the ability to jump to a specific time/date in the logs without having to endlessly scroll.&lt;/p&gt;
&lt;p&gt;To start benefiting from the extended logs, make sure you update the latest version via your Instance Settings page.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of browsing Node-RED logs by timestamp&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/browse-logs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of browsing Node-RED logs by timestamp&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;remote-instance-provisioning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#remote-instance-provisioning&quot;&gt;Remote Instance Provisioning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve updated the provisioning token support to allow you to automatically assign your remote instances to an application within your team.&lt;/p&gt;
&lt;p&gt;The option to assign to a hosted instance is still there, but being able to assign to the appilcation is more generally useful for most workflows on the platform.&lt;/p&gt;
&lt;p&gt;Details available in the &lt;a href=&quot;https://flowfuse.com/changelog/2025/04/device-provisioning/&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;local-login-for-remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#local-login-for-remote-instances&quot;&gt;Local Login for Remote Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the great features of our Remote Instance management is that we enable secure remote access to the Node-RED editor through the platform. To date, this approach has meant we disable direct local access to the editor.&lt;/p&gt;
&lt;p&gt;With the most recent Device Agent release, we&#39;ve added the ability to configure a local user login for the editor. This can be used when the remote instance is not able to reach the FlowFuse platform.&lt;/p&gt;
&lt;p&gt;We&#39;re keen for feedback on this and will continue to explore otherwise to provide secure local access to the remote instance.&lt;/p&gt;
&lt;h2 id=&quot;resource-alerts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#resource-alerts&quot;&gt;Resource Alerts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We expanded the notficiations we send to help you track the health of your Node-RED instances. We will now send notifications if the CPU and/or memory usages exceeds 75% of the available capacity for a prolonged time.&lt;/p&gt;
&lt;p&gt;You can further opt-in or out of these notifications via the instance settings.&lt;/p&gt;
&lt;p&gt;Details available in the &lt;a href=&quot;https://flowfuse.com/changelog/2025/03/resource-notifications/&quot;&gt;changelog&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;changes-to-tags-for-flowfuse%2Fnode-red-containers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#changes-to-tags-for-flowfuse%2Fnode-red-containers&quot;&gt;Changes to tags for &lt;code&gt;flowfuse/node-red&lt;/code&gt; containers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For kubernetes and docker environments, we&#39;ve updated the base container our &lt;code&gt;latest&lt;/code&gt; tag points at to ensure
it defaults to the latest Node.js and Node-RED versions.&lt;/p&gt;
&lt;p&gt;Check the &lt;a href=&quot;https://flowfuse.com/changelog/2025/03/container-tags/&quot;&gt;changelog&lt;/a&gt; entry for full details&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#what-else-is-new%3F&quot;&gt;What Else Is New?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.16 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.16.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/flowfuse-release-2-16/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/</id>
        <title>Part 2: Building an OEE Dashboard with FlowFuse</title>
        <summary>Step-by-step guide to building your own OEE Dashboard.</summary>
        <updated>2025-04-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/&quot;&gt;Part 1&lt;/a&gt;, we explored the fundamentals of OEE, outlined a basic design of the dashboard, and identified the key elements to include in the OEE dashboard.
In this Part 2, we will focus on building the OEE dashboard interface using &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (Node-RED Dashboard 2.0) and FlowFuse, utilizing simulated production and downtime data.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To simplify the development process, we will divide development into five key parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Collecting and configuring data&lt;/li&gt;
&lt;li&gt;Preparing data for calculations&lt;/li&gt;
&lt;li&gt;Calculating OEE and key metrics&lt;/li&gt;
&lt;li&gt;Detailed breakdown of OEE data&lt;/li&gt;
&lt;li&gt;Building the dashboard&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before we start, it is recommended to have a basic knowledge of Node-RED. For that, I recommend this free &lt;a href=&quot;https://node-red-academy.learnworlds.com/course/node-red-getting-started&quot;&gt;Node-RED Fundamental Course&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, ensure that you organize flows into well-structured groups. To match my group organization, I have provided images of the flow for each section. Also, if a Link In node is present at the start, create the group starting from the Link In node and ending at the Link Out node.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin building the OEE Dashboard with FlowFuse, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running FlowFuse Instance:&lt;/strong&gt; Make sure you have a FlowFuse instance set up and running. If you don&#39;t have an account, check out our &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; and learn how to create an instance in FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Dashboard:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (also known as Node-RED Dashboard 2.0 in the community) installed and properly configured on your instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite Contrib Node:&lt;/strong&gt; Ensure you have &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-sqlite&quot;&gt;node-red-contrib-sqlite&lt;/a&gt; installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;preparing-simulated-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#preparing-simulated-data&quot;&gt;Preparing Simulated Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before building the dashboard, we need a data source for production and downtime metrics. This data will serve as input for OEE calculations. We will focus on connecting a real source in the next part, but for now, let&#39;s generate simulated data.&lt;/p&gt;
&lt;div id=&quot;nr-flow-209&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow209 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Simulated Data Generation&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;853fb3a395d833bb&#92;&quot;,&#92;&quot;a96ffd171bf11823&#92;&quot;,&#92;&quot;3d30995a4329eb71&#92;&quot;,&#92;&quot;0f466ba2a885e22a&#92;&quot;,&#92;&quot;f8229c651706b162&#92;&quot;,&#92;&quot;2ceebc93d54adba4&#92;&quot;,&#92;&quot;0c927abd3b139e97&#92;&quot;,&#92;&quot;8222855bc32e9240&#92;&quot;],&#92;&quot;x&#92;&quot;:24,&#92;&quot;y&#92;&quot;:99,&#92;&quot;w&#92;&quot;:1142,&#92;&quot;h&#92;&quot;:182},{&#92;&quot;id&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;aa7bd867fa7daca5&#92;&quot;,&#92;&quot;234aef8a999cb8d9&#92;&quot;,&#92;&quot;d7641c9327f295f8&#92;&quot;,&#92;&quot;c3e96b73cd6ec586&#92;&quot;,&#92;&quot;13f2e851e3f28ec6&#92;&quot;,&#92;&quot;9a444655c076d5a7&#92;&quot;,&#92;&quot;e1fe1b1a4f1ef2e5&#92;&quot;,&#92;&quot;2beb68abc5da93bc&#92;&quot;,&#92;&quot;b83d517fae3c7bbf&#92;&quot;,&#92;&quot;50ebbbfb159a3cbe&#92;&quot;,&#92;&quot;8873774ad339b67e&#92;&quot;,&#92;&quot;77e22b20d1862c7e&#92;&quot;],&#92;&quot;x&#92;&quot;:-6,&#92;&quot;y&#92;&quot;:299,&#92;&quot;w&#92;&quot;:2092,&#92;&quot;h&#92;&quot;:162},{&#92;&quot;id&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;b1f773f4cc2266c6&#92;&quot;,&#92;&quot;cce91928076adb23&#92;&quot;,&#92;&quot;d853a554ecd152b1&#92;&quot;,&#92;&quot;45628fb0ca0a4672&#92;&quot;,&#92;&quot;36ae627ad694fc09&#92;&quot;,&#92;&quot;69afd49e2ceb191b&#92;&quot;,&#92;&quot;808db5612ba1aedc&#92;&quot;,&#92;&quot;6dcd69acd5990793&#92;&quot;],&#92;&quot;x&#92;&quot;:34,&#92;&quot;y&#92;&quot;:479,&#92;&quot;w&#92;&quot;:1202,&#92;&quot;h&#92;&quot;:142},{&#92;&quot;id&#92;&quot;:&#92;&quot;a96ffd171bf11823&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create ProductionData table&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;sql&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS ProductionData (&#92;&#92;n    id INTEGER PRIMARY KEY AUTOINCREMENT,&#92;&#92;n    timestamp DATETIME NOT NULL,&#92;&#92;n    area VARCHAR(255) NOT NULL,&#92;&#92;n    line VARCHAR(100) NOT NULL,  &#92;&#92;n    machine_name VARCHAR(255) NOT NULL,&#92;&#92;n    shift VARCHAR(50) NOT NULL,&#92;&#92;n    shift_duration DECIMAL(5,2) NOT NULL,&#92;&#92;n    good_units INT NOT NULL,&#92;&#92;n    defect_units INT NOT NULL,&#92;&#92;n    total_produced_units INT NOT NULL,&#92;&#92;n    cycle_time DECIMAL(5,2) NOT NULL,&#92;&#92;n    ideal_cycle_time DECIMAL(5,2) NOT NULL,&#92;&#92;n    target_output INT NOT NULL DEFAULT 0,&#92;&#92;n    operating_time INT NOT NULL&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;853fb3a395d833bb&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3d30995a4329eb71&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a96ffd171bf11823&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0f466ba2a885e22a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ceebc93d54adba4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create Downtime table&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;sql&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;CREATE TABLE IF NOT EXISTS DowntimeData (&#92;&#92;n    id INTEGER PRIMARY KEY AUTOINCREMENT,&#92;&#92;n    timestamp DATETIME NOT NULL,&#92;&#92;n    area VARCHAR(255) NOT NULL,&#92;&#92;n    line VARCHAR(100) NOT NULL,  &#92;&#92;n    machine_name VARCHAR(255) NOT NULL,&#92;&#92;n    shift VARCHAR(50) NOT NULL,&#92;&#92;n    downtime_start DATETIME NOT NULL,&#92;&#92;n    downtime_end DATETIME NOT NULL,&#92;&#92;n    downtime_duration_minutes INTEGER NOT NULL,&#92;&#92;n    downtime_type VARCHAR(50) NOT NULL CHECK (downtime_type IN (&#39;Planned&#39;, &#39;Unplanned&#39;)),&#92;&#92;n    downtime_reason TEXT NOT NULL&#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f8229c651706b162&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c927abd3b139e97&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2ceebc93d54adba4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8222855bc32e9240&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;234aef8a999cb8d9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert production data record&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;INSERT INTO ProductionData (&#92;&#92;n    timestamp, &#92;&#92;n    area, &#92;&#92;n    line, &#92;&#92;n    machine_name, &#92;&#92;n    shift, &#92;&#92;n    shift_duration, &#92;&#92;n    good_units, &#92;&#92;n    defect_units, &#92;&#92;n    total_produced_units, &#92;&#92;n    cycle_time, &#92;&#92;n    ideal_cycle_time,  &#92;&#92;n    target_output,&#92;&#92;n    operating_time  &#92;&#92;n) &#92;&#92;nVALUES (&#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;  &#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:1550,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aa7bd867fa7daca5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7641c9327f295f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1970,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cce91928076adb23&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Drop demo downtime data&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;sql&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;Drop table DowntimeData;&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b1f773f4cc2266c6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d853a554ecd152b1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cce91928076adb23&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;45628fb0ca0a4672&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 5&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1120,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c3e96b73cd6ec586&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Click to generate and insert demo data.&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:230,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;13f2e851e3f28ec6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;13f2e851e3f28ec6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Generate simulated production and downtime data&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;function generateProductionData() {&#92;&#92;n    const areas = {&#92;&#92;n        &#92;&#92;&#92;&quot;Pressing&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;Hydraulic Press&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;CNC Press Brake&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Stamping Press&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Power Press&#92;&#92;&#92;&quot;],&#92;&#92;n        &#92;&#92;&#92;&quot;Assembly&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;Robotic Arm&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Screw Insertion Machine&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Pick-and-Place Machine&#92;&#92;&#92;&quot;],&#92;&#92;n        &#92;&#92;&#92;&quot;Packaging&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;Carton Sealing Machine&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Shrink Wrapping Machine&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Bottle Filling and Capping Machine&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Flow Wrapper&#92;&#92;&#92;&quot;]&#92;&#92;n    };&#92;&#92;n&#92;&#92;n    const shifts = [&#92;&#92;&#92;&quot;Shift 1&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Shift 2&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Shift 3&#92;&#92;&#92;&quot;];&#92;&#92;n    const shiftStartTimes = {&#92;&#92;n        &#92;&#92;&#92;&quot;Shift 1&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;00:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;Shift 2&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;08:00:00&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;Shift 3&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;16:00:00&#92;&#92;&#92;&quot;&#92;&#92;n    };&#92;&#92;n&#92;&#92;n    const uniqueShortCodes = {&#92;&#92;n        &#92;&#92;&#92;&quot;Pressing&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;HP&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;PB&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;SP&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;PP&#92;&#92;&#92;&quot;],&#92;&#92;n        &#92;&#92;&#92;&quot;Assembly&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;RA&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;SIM&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;P and P&#92;&#92;&#92;&quot;],&#92;&#92;n        &#92;&#92;&#92;&quot;Packaging&#92;&#92;&#92;&quot;: [&#92;&#92;&#92;&quot;CSM&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;SWM&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;BFCM&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;FW&#92;&#92;&#92;&quot;]&#92;&#92;n    };&#92;&#92;n&#92;&#92;n    const downtimeTypes = [&#92;&#92;&#92;&quot;Planned&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Unplanned&#92;&#92;&#92;&quot;];&#92;&#92;n    const plannedDowntimeReasons = [&#92;&#92;n        &#92;&#92;&#92;&quot;Scheduled Maintenance&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Equipment Upgrades&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Shift Changeover&#92;&#92;&#92;&quot;,&#92;&#92;n        &#92;&#92;&#92;&quot;Tool Changeover&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Calibration and Quality Checks&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Cleaning and Sanitation&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Planned Power Outage&#92;&#92;&#92;&quot;&#92;&#92;n    ];&#92;&#92;n    const unplannedDowntimeReasons = [&#92;&#92;n        &#92;&#92;&#92;&quot;Power Failure&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Material Shortage&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Technical Fault&#92;&#92;&#92;&quot;, &#92;&#92;&#92;&quot;Operator Unavailable&#92;&#92;&#92;&quot;&#92;&#92;n    ];&#92;&#92;n&#92;&#92;n    const data = [];&#92;&#92;n    const downtimeData = [];&#92;&#92;n    const now = new Date();&#92;&#92;n&#92;&#92;n    const normalizeTimestamp = (timestamp) =&amp;gt; timestamp.toISOString().split(&#92;&#92;&#92;&quot;T&#92;&#92;&#92;&quot;).join(&#92;&#92;&#92;&quot; &#92;&#92;&#92;&quot;).slice(0, 19);&#92;&#92;n&#92;&#92;n    for (let i = 0; i &amp;lt; 30; i++) {&#92;&#92;n        const date = new Date();&#92;&#92;n        date.setDate(now.getDate() - i);&#92;&#92;n        const formattedDate = date.toISOString().split(&#92;&#92;&#92;&quot;T&#92;&#92;&#92;&quot;)[0];&#92;&#92;n&#92;&#92;n        shifts.forEach(shift =&amp;gt; {&#92;&#92;n            const shiftStart = shiftStartTimes[shift];&#92;&#92;n            const shiftTimestamp = new Date(`${formattedDate}T${shiftStart}`);&#92;&#92;n&#92;&#92;n            Object.entries(areas).forEach(([area, machines]) =&amp;gt; {&#92;&#92;n                machines.forEach((_, index) =&amp;gt; {&#92;&#92;n                    const randomCode = uniqueShortCodes[area][Math.floor(Math.random() * uniqueShortCodes[area].length)];&#92;&#92;n                    const uniqueID = Math.floor(10000 + Math.random() * 90000);&#92;&#92;n                    const shortMachineName = `${randomCode}-${uniqueID}`;&#92;&#92;n&#92;&#92;n                    const shiftDuration = 8;&#92;&#92;n                    let totalDowntimeMinutes = 0;&#92;&#92;n                    let downtimeEvents = [];&#92;&#92;n&#92;&#92;n                    // Increase downtime frequency (up to 4 events per shift)&#92;&#92;n                    const numDowntimes = Math.floor(Math.random() * 4) + 1;&#92;&#92;n&#92;&#92;n                    for (let d = 0; d &amp;lt; numDowntimes; d++) {&#92;&#92;n                        if (Math.random() &amp;lt; 0.75) {  // Increase probability of downtime&#92;&#92;n                            let downtimeMinutes = Math.floor(5 + Math.random() * 10); // Shorter downtimes (5-15 mins)&#92;&#92;n                            totalDowntimeMinutes += downtimeMinutes;&#92;&#92;n&#92;&#92;n                            const downtimeStartMinutes = Math.floor(Math.random() * (shiftDuration * 60 - downtimeMinutes));&#92;&#92;n                            const downtimeStart = new Date(shiftTimestamp);&#92;&#92;n                            downtimeStart.setMinutes(downtimeStart.getMinutes() + downtimeStartMinutes);&#92;&#92;n&#92;&#92;n                            const downtimeEnd = new Date(downtimeStart);&#92;&#92;n                            downtimeEnd.setMinutes(downtimeEnd.getMinutes() + downtimeMinutes);&#92;&#92;n&#92;&#92;n                            const downtimeType = downtimeTypes[Math.floor(Math.random() * downtimeTypes.length)];&#92;&#92;n                            const downtimeReason = downtimeType === &#92;&#92;&#92;&quot;Planned&#92;&#92;&#92;&quot;&#92;&#92;n                                ? plannedDowntimeReasons[Math.floor(Math.random() * plannedDowntimeReasons.length)]&#92;&#92;n                                : unplannedDowntimeReasons[Math.floor(Math.random() * unplannedDowntimeReasons.length)];&#92;&#92;n&#92;&#92;n                            downtimeEvents.push({&#92;&#92;n                                timestamp: normalizeTimestamp(shiftTimestamp),&#92;&#92;n                                area,&#92;&#92;n                                machine_name: shortMachineName,&#92;&#92;n                                shift,&#92;&#92;n                                downtime_start: normalizeTimestamp(downtimeStart),&#92;&#92;n                                downtime_end: normalizeTimestamp(downtimeEnd),&#92;&#92;n                                downtime_duration_minutes: downtimeMinutes,&#92;&#92;n                                downtime_reason: downtimeReason,&#92;&#92;n                                downtime_type: downtimeType,&#92;&#92;n                                line: `Line-${index + 1}`&#92;&#92;n                            });&#92;&#92;n                        }&#92;&#92;n                    }&#92;&#92;n&#92;&#92;n                    const operatingTime = (shiftDuration * 60 - totalDowntimeMinutes) * 60;&#92;&#92;n                    let efficiency = Math.random() * 0.2 + 0.75;&#92;&#92;n                    let targetOutput = Math.floor(operatingTime / 3) || 1;&#92;&#92;n                    let totalProduced = Math.floor(targetOutput * efficiency);&#92;&#92;n                    totalProduced = Math.min(totalProduced, targetOutput);&#92;&#92;n&#92;&#92;n                    const defectRate = Math.random() * 0.02 + 0.01;&#92;&#92;n                    const defectUnits = Math.floor(totalProduced * defectRate);&#92;&#92;n                    const goodUnits = totalProduced - defectUnits;&#92;&#92;n&#92;&#92;n                    data.push({&#92;&#92;n                        timestamp: normalizeTimestamp(shiftTimestamp),&#92;&#92;n                        area,&#92;&#92;n                        machine_name: shortMachineName,&#92;&#92;n                        shift,&#92;&#92;n                        shift_duration: shiftDuration,&#92;&#92;n                        operating_time: operatingTime - totalDowntimeMinutes * 60,&#92;&#92;n                        good_units: goodUnits,&#92;&#92;n                        defect_units: defectUnits,&#92;&#92;n                        total_produced_units: totalProduced,&#92;&#92;n                        target_output: targetOutput,&#92;&#92;n                        line: `Line-${index + 1}`&#92;&#92;n                    });&#92;&#92;n&#92;&#92;n                    downtimeData.push(...downtimeEvents);&#92;&#92;n                });&#92;&#92;n            });&#92;&#92;n        });&#92;&#92;n    }&#92;&#92;n&#92;&#92;n    return [&#92;&#92;n        { payload: data },&#92;&#92;n        { payload: downtimeData }&#92;&#92;n    ];&#92;&#92;n}&#92;&#92;n&#92;&#92;nconst productionDataSet = generateProductionData();&#92;&#92;n&#92;&#92;nreturn [&#92;&#92;n    { payload: productionDataSet[0].payload },&#92;&#92;n    { payload: productionDataSet[1].payload }&#92;&#92;n];&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9a444655c076d5a7&#92;&quot;],[&#92;&quot;8873774ad339b67e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9a444655c076d5a7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1060,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e1fe1b1a4f1ef2e5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e1fe1b1a4f1ef2e5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;10 msg/s&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;rate&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1280,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;234aef8a999cb8d9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b83d517fae3c7bbf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Insert downtime data record&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;INSERT INTO DowntimeData ( timestamp, area, line, machine_name, shift, &#92;&#92;n    downtime_start, downtime_end, downtime_duration_minutes, &#92;&#92;n    downtime_type, downtime_reason&#92;&#92;n)  &#92;&#92;nVALUES (&#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;, &#92;&#92;n    &#39;&#39;,&#92;&#92;n    &#39;&#39;,  &#92;&#92;n    ,  &#92;&#92;n    &#39;&#39;,  &#92;&#92;n    &#39;&#39;  &#92;&#92;n);&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:1550,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2beb68abc5da93bc&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;50ebbbfb159a3cbe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 8&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1970,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8873774ad339b67e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1060,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;77e22b20d1862c7e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;77e22b20d1862c7e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;10 msg/s&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;rate&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1280,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b83d517fae3c7bbf&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;69afd49e2ceb191b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Drop demo production data&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;sql&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;Drop table ProductionData;&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;36ae627ad694fc09&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;808db5612ba1aedc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;69afd49e2ceb191b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6dcd69acd5990793&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 4&#92;&quot;,&#92;&quot;active&#92;&quot;:false,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1120,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;853fb3a395d833bb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0f466ba2a885e22a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f8229c651706b162&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3f2126c3c00b9e0d&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8222855bc32e9240&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aa7bd867fa7daca5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1780,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d7641c9327f295f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b1f773f4cc2266c6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;45628fb0ca0a4672&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2beb68abc5da93bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;07a3d5b9075ff846&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1780,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;50ebbbfb159a3cbe&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;36ae627ad694fc09&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlite&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fa7147e04d4d5ec3&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;c0550db87d6fb947&#92;&quot;,&#92;&quot;mydb&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;sqlquery&#92;&quot;:&#92;&quot;msg.topic&#92;&quot;,&#92;&quot;sql&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6dcd69acd5990793&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1ae6d7f7fdb60191&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;sqlitedb&#92;&quot;,&#92;&quot;db&#92;&quot;:&#92;&quot;sqllite&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;RWC&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow209.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-209&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Import the provided flow for data generation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;Deploy&lt;/strong&gt; button to activate the flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On deployment, it will create two SQLite tables: &lt;code&gt;ProductionData&lt;/code&gt; and &lt;code&gt;DowntimeData&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find the &lt;strong&gt;Inject node&lt;/strong&gt; labeled &lt;em&gt;Click to generate and insert demo data&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the inject node to trigger data generation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The flow will generate data with the following fields:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Demo Production and Downtime data object&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/demo-data-props.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Demo Production and Downtime data object&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;collecting-and-configuring-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#collecting-and-configuring-data&quot;&gt;Collecting and Configuring Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the simulated data is generated and stored in SQLite, the next step is to create a flow for configuration settings. These settings will be used across the entire flow, allowing the flow to be reused by simply modifying the settings. The configured data will then be collected for use in the OEE dashboard.&lt;/p&gt;
&lt;h4 id=&quot;adding-flow-to-configure-settings%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#adding-flow-to-configure-settings%3A&quot;&gt;Adding flow to configure settings:&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;strong&gt;&amp;quot;+&amp;quot;&lt;/strong&gt; to create a new flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name the newly created flow to &lt;strong&gt;OEE Dashboard for Line-1&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; onto the canvas, double-click it, and add the following elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;flow.line&lt;/code&gt; to &lt;code&gt;&amp;quot;Line-1&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;flow.shift_duration&lt;/code&gt; to &lt;code&gt;12&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;flow.shiftDuration24h&lt;/code&gt; to &lt;code&gt;24&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject node&lt;/strong&gt;, set it to trigger on deploy by enabling &lt;strong&gt;Inject once after X seconds&lt;/strong&gt; (set delay to &lt;code&gt;0.1&lt;/code&gt; seconds).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to apply changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this flow, we are configuring the production line based on the demo data, specifically for &lt;strong&gt;Line-1&lt;/strong&gt;, as we are building the OEE dashboard for this line. The settings define the shift duration for the last &lt;strong&gt;X&lt;/strong&gt; hours used in OEE calculations and the total shift duration within a &lt;strong&gt;24-hour&lt;/strong&gt; period.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow to set basic configuration settings that will be used across the OEE dashboard flow for calculations.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/configuration-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow to set basic configuration settings that will be used across the OEE dashboard flow for calculations.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;retrieving-data-from-sqlite%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#retrieving-data-from-sqlite%3A&quot;&gt;Retrieving Data from SQLite:&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;Inject node&lt;/strong&gt; and configure it to trigger at regular intervals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; and add following elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.params&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$startTime&lt;/code&gt; to &lt;code&gt;$moment($millis() - ($number($flowContext(&#39;shift_duration&#39;)) * 60 * 60 * 1000)).format(&#39;YYYY-MM-DD HH:mm:ss&#39;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$endTime&lt;/code&gt; to &lt;code&gt;$moment($millis()).format(&#39;YYYY-MM-DD HH:mm:ss&#39;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.params.$line&lt;/code&gt; to &lt;code&gt;flow.line&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag an &lt;strong&gt;SQLite node&lt;/strong&gt; and insert the following query:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-204&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-204&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; good_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; defect_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; target_output&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; ProductionData&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $startTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $endTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-204&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Change node onto the canvas and set the following element to store the retrived production data result as new property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.productionData&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the Inject node’s output to the input of the Change node that sets parameters. Then, connect the Change node’s output to the input of the SQLite node that retrieves production data. Finally, connect the SQLite node’s output to the input of last change node we added.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;SQLite node&lt;/strong&gt; and insert the following query:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-227&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-227&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; downtime_start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; downtime_duration_minutes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; downtime_reason&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; DowntimeData&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $startTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $endTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-227&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Change node onto the canvas and set the following element to store the retrived production data result as new property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.downtimeData&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the SQLite node’s output to the input of last change node we added.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, drag the Link Out node onto the canvas and connect it to the last Change node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow that retrives the data from the sqlite table&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sqlite-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow that retrives the data from the sqlite table&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;preparing-data-for-oee-calculations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#preparing-data-for-oee-calculations&quot;&gt;Preparing Data for OEE Calculations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have a flow to retrieve production and downtime data, we can calculate key OEE metrics. The total number of good units, defective units, total produced units, target output, and downtime duration are summed across all production lines. Using these values, we can calculate availability, performance, and quality for the entire production system, which can then be used to calculate OEE.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;link in node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;link out node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag two &lt;strong&gt;Change nodes&lt;/strong&gt; onto the canvas and connect them to the &lt;strong&gt;Link In&lt;/strong&gt; node.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the first Change node, set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;production_data&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In the second Change node, set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;downtime_data&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split node&lt;/strong&gt; onto the canvas and connect it to the first &lt;strong&gt;Change node&lt;/strong&gt;, the one setting &lt;code&gt;production_data&lt;/code&gt;. Configure the &lt;strong&gt;Split node&lt;/strong&gt; so that &lt;code&gt;msg.payload&lt;/code&gt; is assigned to &lt;code&gt;production_data&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag three &lt;strong&gt;Join nodes&lt;/strong&gt; onto the canvas and connect them to the &lt;strong&gt;Split node&lt;/strong&gt; to sum individual data points. Configure each &lt;strong&gt;Join node&lt;/strong&gt; with the following settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mode: Reduce Sequence&lt;/li&gt;
&lt;li&gt;Initial Value: 0&lt;/li&gt;
&lt;li&gt;Fix-up Expression: &lt;code&gt;$A&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the reduce expressions as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First Join Node: &lt;code&gt;$A + msg.payload.total_produced_units&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Second Join Node: &lt;code&gt;$A + msg.payload.good_units&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Third Join Node: &lt;code&gt;$A + msg.payload.target_output&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag three &lt;strong&gt;Change nodes&lt;/strong&gt; onto the canvas and connect each to a &lt;strong&gt;Join node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure these &lt;strong&gt;Change nodes&lt;/strong&gt; to store the summed values using the following variables to flow context:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;total_produced_units&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;total_good_units&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;total_target_output&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;Change node&lt;/strong&gt; that sets the retrieved downtime data to &lt;code&gt;msg.payload&lt;/code&gt;, for switch node set the Property to &lt;code&gt;msg.payload&lt;/code&gt; and add the following conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is not empty.&lt;/li&gt;
&lt;li&gt;Otherwise.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split node&lt;/strong&gt; onto the canvas and connect it to the first output of the &lt;strong&gt;Switch node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Join node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;Split node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the &lt;strong&gt;Join node&lt;/strong&gt; with the following settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mode: Reduce Sequence&lt;/li&gt;
&lt;li&gt;Initial Value: 0&lt;/li&gt;
&lt;li&gt;Fix-up Expression: &lt;code&gt;$A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reduce Expression: &lt;code&gt;$A + payload.downtime_duration_minutes&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;Join node&lt;/strong&gt;, Configure this &lt;strong&gt;Change node&lt;/strong&gt; to store the total downtime duration in the flow context with following element:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;flow.total_downtime&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another Change node onto the canvas and connect it to the second output of the Switch node, Set this Change node to store 0 in the flow context for total_downtime with following element:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;flow.total_downtime&lt;/code&gt; to 0&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;14&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Link Out&lt;/strong&gt; node onto the canvas and connect it to any of the Change nodes that store the summed metrics in the flow context.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow to prepare the data necessary to calculate OEE and all its three components.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/preparing-data-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow to prepare the data necessary to calculate OEE and all its three components.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;calculating-oee-and-key-metrics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#calculating-oee-and-key-metrics&quot;&gt;Calculating OEE and Key Metrics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have all the necessary pieces, we can calculate the key metrics for OEE: Availability, Performance, and Quality and later OEE.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Link In node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change node&lt;/strong&gt; and add element as following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.quality&lt;/code&gt; to &lt;code&gt;($flowContext(&#39;total_good_units&#39;) / $flowContext(&#39;total_produced_units&#39;)) * 100&lt;/code&gt; as JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.availability&lt;/code&gt; to &lt;code&gt;(($flowContext(&#39;shift_duration&#39;) - $flowContext(&#39;total_downtime&#39;)) / $flowContext(&#39;shift_duration&#39;)) * 100&lt;/code&gt; as JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.performance&lt;/code&gt; to &lt;code&gt;($flowContext(&#39;total_produced_units&#39;) / $flowContext(&#39;target_output&#39;)) * 100&lt;/code&gt; as JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.oee&lt;/code&gt; to &lt;code&gt;$round(((msg.availability / 100) * (msg.performance / 100) * (msg.quality / 100)) * 100, 2)&lt;/code&gt; as JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.quality&lt;/code&gt;to &lt;code&gt;$round(msg.quality, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.availability&lt;/code&gt; to &lt;code&gt;$round(msg.availability, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.performance&lt;/code&gt; to &lt;code&gt;$round(msg.performance, 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.productionData&lt;/code&gt; to JSONata expression:&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-507&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-507&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;reason&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Total Good Units Produced&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;units&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $flowContext(&lt;span class=&quot;token string&quot;&gt;&quot;total_good_units&quot;&lt;/span&gt;)&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;series&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Total Defective Units Produced&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;units&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $number($flowContext(&lt;span class=&quot;token string&quot;&gt;&quot;total_produced_units&quot;&lt;/span&gt;)) - $number($flowContext(&lt;span class=&quot;token string&quot;&gt;&quot;total_good_units&quot;&lt;/span&gt;))&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-507&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Link Out node&lt;/strong&gt; and connect it to the &lt;strong&gt;Change node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a separate &lt;strong&gt;Link In&lt;/strong&gt; node for visualization and keep it in a separate flow. This will be the &lt;strong&gt;Link In&lt;/strong&gt; node where all the calculated final data for visualization will be stored.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect &lt;strong&gt;link out&lt;/strong&gt; node to this &lt;strong&gt;link in&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow that calculates availability, quality, performance, and OEE, and also prepares production data for visualization.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/calculate-oee-and-key-metrics.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow that calculates availability, quality, performance, and OEE, and also prepares production data for visualization.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;detailed-breakdown-of-oee-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#detailed-breakdown-of-oee-data&quot;&gt;Detailed Breakdown of OEE Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have calculated the OEE and other key metrics. However, as discussed in the planning section of our previous article, we will also visualize recent downtime events, a downtime summary, the top underperforming machines (OEE-wise), and the OEE trend over the last 30 days on the dashboard.&lt;/p&gt;
&lt;p&gt;Let’s do that.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;link in node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;link out node&lt;/strong&gt; that is part of the SQLite flow, which is also connected to the change node that sets the retrieved downtime result to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; onto the canvas and set the following element: &lt;code&gt;Set msg.downtime_data to msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;downtime-summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#downtime-summary&quot;&gt;Downtime Summary&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function node&lt;/strong&gt; onto the canvas and add the following JavaScript to calculate the downtime summary:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-559&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-559&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateDowntimeByReason&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;downtimeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;downtimeData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; downtimeData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; f&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; summary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   downtimeData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; downtime_reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; downtime_duration_minutes &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       summary&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;downtime_reason&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;summary&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;downtime_reason&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; downtime_duration_minutes&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;summary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token literal-property property&quot;&gt;downtime_reason&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token literal-property property&quot;&gt;downtime_duration_minutes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; duration&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateDowntimeByReason&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-559&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;change node&lt;/strong&gt; onto the canvas and set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.downtimeSummary&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;link out&lt;/strong&gt; node and connect it to the change node that sets &lt;code&gt;msg.downtime_data&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect this &lt;strong&gt;link out node&lt;/strong&gt; to the &lt;strong&gt;link in node&lt;/strong&gt; that we added earlier to receive all the calculated metrics for visualization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;recent-downtime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#recent-downtime&quot;&gt;Recent Downtime&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and set the property to &lt;strong&gt;msg.payload&lt;/strong&gt;. Add the following condition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;is not empty&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;otherwise&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;first output&lt;/strong&gt; of the &lt;strong&gt;Switch&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Sort&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Split&lt;/strong&gt; node. Set the sort to &lt;strong&gt;&amp;quot;message sequence&amp;quot;&lt;/strong&gt;, key to &lt;strong&gt;&lt;code&gt;msg.payload.downtime_start&lt;/code&gt;&lt;/strong&gt;, and order to &lt;strong&gt;&amp;quot;descending.&amp;quot;&lt;/strong&gt; This will sort the downtime data from &lt;strong&gt;most recent to oldest&lt;/strong&gt; based on its start time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Join&lt;/strong&gt; node onto the canvas and set the mode to &lt;strong&gt;automatic&lt;/strong&gt;, then connect it to the &lt;strong&gt;Sort&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and set the following element:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Set &lt;code&gt;msg.recentDowntime&lt;/code&gt; to &lt;code&gt;payload^(10)&lt;/code&gt; as a JSONata expression.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the &lt;strong&gt;Change&lt;/strong&gt; node to the &lt;strong&gt;Link Out&lt;/strong&gt; node that was added before.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;top-underperforming-machines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#top-underperforming-machines&quot;&gt;Top Underperforming Machines&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Function&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Link In&lt;/strong&gt; node that is receiving the &lt;strong&gt;SQLite result&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following &lt;strong&gt;JavaScript&lt;/strong&gt; code to the &lt;strong&gt;Function&lt;/strong&gt; node:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-653&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-653&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; productionData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;production_data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; downtimeEvents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;downtime_data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shiftDuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;shift_duration&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Convert hours to minutes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Group production data by machine (including area)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; machineData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;productionData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;total_produced_units&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;good_units&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;target_output&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;area &lt;span class=&quot;token comment&quot;&gt;// Store area&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;good_units &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;good_units&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; oeeResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;machineData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;machineName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; machineData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;machineName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; machineDowntime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; downtimeEvents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;machine_name &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; machineName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateOEE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; downtime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;availability&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;performance&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;quality&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;oee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalDowntime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; downtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;downtime_duration_minutes &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;number&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;downtime_duration_minutes &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; acc&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; availability &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shiftDuration &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; totalDowntime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; shiftDuration&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        availability &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; availability&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; performance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; quality &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;good_units &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; oee &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; availability &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; performance &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; quality&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;availability&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;availability &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;performance&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;performance &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;quality&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;quality &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;oee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;oee &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; metrics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateOEE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; machineDowntime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;machine_name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; machineName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;oee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oee&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Filter only machines with OEE &amp;lt; 85&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; oeeResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;machine&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; machine&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;oee &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-653&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flow that prepares the Recent Downtime, Downtime Summary, and Top Underperforming Machines (OEE-wise)
&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/downtime-events-summery-oee-machine-wise.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flow that prepares the Recent Downtime, Downtime Summary, and Top Underperforming Machines (OEE-wise)&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;oee-trend-for-the-last-30-days&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#oee-trend-for-the-last-30-days&quot;&gt;OEE Trend for the Last 30 Days&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now, to calculate the OEE for the last 30 days, we need the complete production and downtime data for that period. However, the current SQLite flow retrieves only the last 12 hours. Therefore, we need another SQLite flow to retrieve data from the last 30 days.&lt;/p&gt;
&lt;h5 id=&quot;retrieving-production-and-downtime-data-for-the-last-30-days&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#retrieving-production-and-downtime-data-for-the-last-30-days&quot;&gt;Retrieving Production and Downtime Data for the Last 30 Days&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Copy the existing &lt;strong&gt;SQLite flow&lt;/strong&gt; from the &lt;strong&gt;Inject node&lt;/strong&gt; to the &lt;strong&gt;Change node&lt;/strong&gt; that sets the retrieved downtime result to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;strong&gt;Change node&lt;/strong&gt; that sets the parameters for the SQL query, keep only the element setting the line parameter, and remove the rest.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify the first SQLite node&#39;s SQL query to the following:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-683&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-683&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    machine_name &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    area &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    line &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    total_produced_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    good_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; good_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    defect_units &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; defect_units&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    target_output &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; target_output&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; ProductionData&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;now&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;-30 days&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-683&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Modify the second SQLite node&#39;s SQL query to the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-691&quot;&gt;
  &lt;pre class=&quot;language-sql&quot;&gt;&lt;code id=&quot;code-691&quot; class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    machine_name &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; machine_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    downtime_start &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; downtime_start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    downtime_duration_minutes &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; downtime_duration_minutes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    downtime_reason &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; downtime_reason&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; DowntimeData&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;BETWEEN&lt;/span&gt; $startTime &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; $endTime&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-691&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h5 id=&quot;calculating-last-30d-days-oee&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#calculating-last-30d-days-oee&quot;&gt;Calculating last 30d days OEE&lt;/a&gt;&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Link Out node&lt;/strong&gt; onto the canvas and connect it to the last &lt;strong&gt;Change node&lt;/strong&gt; of the SQLite flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Link In node&lt;/strong&gt; onto the canvas and connect it to the last &lt;strong&gt;Link Out node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Function node&lt;/strong&gt; onto the canvas, add the following JavaScript, and connect the Function node to the &lt;strong&gt;Link In node&lt;/strong&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-712&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-712&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; productionData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;production_data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; downtimeData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;downtime_data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;line&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; shiftDuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;shiftDuration24h&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; groupedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;productionData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;line &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalShiftDuration&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; shiftDuration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalGoodUnits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalProducedUnits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalDowntimeSeconds&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalCycleTime&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;cycleCount&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;totalTargetOutput&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalGoodUnits &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;good_units&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalProducedUnits &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_produced_units&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalCycleTime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cycle_time&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cycleCount&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalTargetOutput &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target_output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;downtimeData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;downtime&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;downtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;line &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; downtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            groupedData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalDowntimeSeconds &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; downtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;downtime_duration_minutes &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; oeeResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;groupedData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; avgCycleTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cycleCount &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalCycleTime &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cycleCount &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; availableTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalShiftDuration &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalDowntimeSeconds&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; availability &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; availableTime &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalShiftDuration&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; performance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalTargetOutput &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalProducedUnits &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalTargetOutput &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; quality &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalProducedUnits &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalGoodUnits &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalProducedUnits &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; oee &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;availability &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; performance &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; quality &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; availability&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; performance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; quality&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oee&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Sort data by timestamp (oldest to most recent)&lt;/span&gt;&lt;br /&gt;oeeResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timestamp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; oeeResults&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-712&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Change node&lt;/strong&gt; onto the canvas and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.oeeTrend&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the &lt;strong&gt;Link Out node&lt;/strong&gt; onto the canvas and connect it to the &lt;strong&gt;Change node&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect this &lt;strong&gt;Link Out node&lt;/strong&gt; to the &lt;strong&gt;Link In node&lt;/strong&gt; that was added earlier to receive all the calculated metrics for visualization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Flows that calculate the OEE for each day over the last 30 days&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-trend.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flows that calculate the OEE for each day over the last 30 days.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;building-the-oee-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#building-the-oee-dashboard&quot;&gt;Building the OEE Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that the key OEE metrics have been calculated and detailed insights into production performance have been gathered, it is time to bring everything together in a visually intuitive and interactive dashboard. The OEE dashboard will provide real-time visibility into availability, performance, and quality while also displaying recent downtime events, downtime summaries, underperforming machines, and historical OEE trends.&lt;/p&gt;
&lt;p&gt;Using FlowFuse Dashboard (Node-RED Dashboard 2.0), a clean and efficient interface will be designed, allowing operators and decision-makers to monitor production efficiency at a glance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a Switch node onto the canvas, set the property to &lt;code&gt;msg.oee&lt;/code&gt;, and add the condition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Is not null&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect it to the Link-In node that receives calculated metrics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Change node, set &lt;code&gt;msg.oee&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;, and connect it to a Gauge widget.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new Group on a new page named &lt;strong&gt;Line-1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the page layout to &lt;strong&gt;Grid&lt;/strong&gt;, adjust the range from &lt;strong&gt;0 to 100&lt;/strong&gt;, and label the gauge &lt;strong&gt;OEE&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Half Gauge&lt;/strong&gt; as the type, set the style to &lt;strong&gt;Rounded&lt;/strong&gt;, and adjust the width and height to &lt;strong&gt;6&lt;/strong&gt; and &lt;strong&gt;3&lt;/strong&gt; for both the group and the widget.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat these steps for &lt;code&gt;msg.quality&lt;/code&gt;, &lt;code&gt;msg.availability&lt;/code&gt;, and &lt;code&gt;msg.performance&lt;/code&gt;, ensuring each has a separate Group with the correct label.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Switch node for &lt;code&gt;msg.productionData&lt;/code&gt; and connect it to a Change node setting &lt;code&gt;msg.productionData&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Is not null&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat this step for &lt;code&gt;msg.downtimeSummary&lt;/code&gt;, &lt;code&gt;msg.recentDowntime&lt;/code&gt;, &lt;code&gt;msg.topUnderPerformingMachines&lt;/code&gt;, and &lt;code&gt;msg.oeeTrend&lt;/code&gt;, ensuring each has a separate Switch node and Change node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Bar Chart widget, create a new Group, set the width to &lt;strong&gt;6&lt;/strong&gt; and height to &lt;strong&gt;8&lt;/strong&gt; for both the group and widget, label it &lt;strong&gt;Production Data&lt;/strong&gt;, group data by &lt;strong&gt;Stacks&lt;/strong&gt;, and map &lt;strong&gt;X to series&lt;/strong&gt; and &lt;strong&gt;Y to units&lt;/strong&gt;. Connect it to the node setting &lt;code&gt;msg.productionData&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Duplicate the chart for &lt;strong&gt;Downtime Summary&lt;/strong&gt;, mapping &lt;strong&gt;X to downtime_reason&lt;/strong&gt; and &lt;strong&gt;Y to downtime_duration_minutes&lt;/strong&gt;, and connect it to the node setting &lt;code&gt;msg.downtimeSummary&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Table widget, create a new Group, set width &lt;strong&gt;6&lt;/strong&gt; and height &lt;strong&gt;2&lt;/strong&gt; for both the group and widget, label it &lt;strong&gt;Recent Downtime Events&lt;/strong&gt;, set max rows to &lt;strong&gt;5&lt;/strong&gt;, and add columns with keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;machine_name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;downtime_start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;downtime_duration_minutes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;downtime_reason&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect it to the node setting &lt;code&gt;msg.recent_downtime&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Duplicate the table for &lt;strong&gt;Top Underperforming Machines&lt;/strong&gt;, adding columns with keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;machine_name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;area&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oee&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect it to &lt;code&gt;msg.topUnderPerformingMachines&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a Line Chart widget, create a new Group, set width &lt;strong&gt;12&lt;/strong&gt; and height &lt;strong&gt;5&lt;/strong&gt; for both the group and widget, label it &lt;strong&gt;Daily OEE Trend Over 24 Hours&lt;/strong&gt;, set X-axis to &lt;strong&gt;Timescale&lt;/strong&gt;, format &lt;strong&gt;Y-l-d&lt;/strong&gt;, and map &lt;strong&gt;X to &lt;code&gt;date&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;Y to &lt;code&gt;oee&lt;/code&gt;&lt;/strong&gt;. Connect it to the Change node setting &lt;code&gt;msg.oeeTrend&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the dashboard by clicking the Dashboard 2.0 button located at the top-right corner of the Dashboard 2.0 sidebar.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard UI flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard UI flow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Your OEE dashboard is now set up and ready to use. It will visualize key metrics, including OEE, quality, availability, performance, production data, downtime events, and machine performance trends.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard results without proper theming and styling&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-without-style.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard results without proper theming and styling.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard results without proper theming and styling&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-without-style-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard results without proper theming and styling&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, the dashboard may not yet look exactly as it did in the previous design or intended layout. Some components may not align correctly with adjacent components in terms of width and height. Additionally, on different screens, you may notice layout inconsistencies, and the top header elements, such as the OEE Dashboard title and logo is missing.&lt;/p&gt;
&lt;p&gt;Do not worry—in the next part of this series, we will style the dashboard to match the original design. Later, we will demonstrate how to connect it to a real data source, scale it across your production lines, and explain how you can use this dashboard to improve production efficiency.&lt;/p&gt;
&lt;h2 id=&quot;what-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/#what-next%3F&quot;&gt;What Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Part 3 of this series will follow soon. In the meantime, if you’re excited to quickly launch your OEE dashboard in your factory environment, don’t delay! &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Register for a FlowFuse account&lt;/a&gt; now and initiate your journey with our new effective, ready-made &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;OEE Dashboard Blueprint&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/</id>
        <title>Part 1: Building an OEE Dashboard with FlowFuse</title>
        <summary>Defining OEE and Planning an Effective Dashboard</summary>
        <updated>2025-04-01T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;OEE (Overall Equipment Effectiveness) is a KPI used in manufacturing to measure equipment performance based on availability, efficiency, and quality.&lt;/p&gt;
&lt;p&gt;To effectively track this KPI, an OEE dashboard is built, but creating one can be complex, especially when consolidating data from various sources, with limited flexibility to integrate data across different systems. Additionally, building a customizable dashboard to suit specific needs adds another layer of complexity.&lt;/p&gt;
&lt;p&gt;With FlowFuse, it&#39;s possible to build a customized, OEE Dashboard, without writing any code, that can provide real-time production data based on your needs.&lt;/p&gt;
&lt;p&gt;In this first part of a new blog series on building an OEE dashboard with FlowFuse, we explain the concept of OEE, how it is calculated, and outline the basic plan for the dashboard. In that plan, we cover the scope of OEE calculation, key metrics, visualization strategies, and the expected design of the dashboard.&lt;/p&gt;
&lt;p&gt;Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;what-is-oee%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#what-is-oee%3F&quot;&gt;What is OEE?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Overall Equipment Effectiveness (OEE) is a crucial metric in manufacturing that assesses the productivity of equipment through three key components. These components evaluate the efficiency of equipment during the production process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Availability:&lt;/strong&gt; How often does the equipment perform when needed?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance:&lt;/strong&gt; How much product does the equipment produce?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production Quality:&lt;/strong&gt; How many high-quality products does the equipment produce?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The concept of OEE was introduced by Seiichi Nakajima in the 1960s as part of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Total_productive_maintenance&quot;&gt;Total Productive Maintenance (TPM)&lt;/a&gt; initiative in Japan. Nakajima, an engineer at the Japan Institute of Plant Maintenance (JIPM), developed OEE to measure and enhance manufacturing productivity by identifying inefficiencies. This metric has since become widely adopted across the manufacturing industry. Today, OEE remains one of the most critical KPIs, with a really huge number of manufacturers considering it either important or very important for improving production efficiency and minimizing waste.&lt;/p&gt;
&lt;p&gt;Measuring and improving OEE allows you to improve the utilization of existing machinery and improves operational efficiency. In many cases, improving OEE is the most strategic and cost-effective approach to increasing output.&lt;/p&gt;
&lt;h2 id=&quot;how-is-oee-calculated%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#how-is-oee-calculated%3F&quot;&gt;How is OEE calculated?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OEE is calculated using the formula:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;OEE (%) = Availability × Performance × Quality&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Availability (%) = (Operating Time ÷ Planned Production Time) × 100&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Performance (%) = (Actual Output ÷ Maximum Possible Output) × 100&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Quality (%) = (Good Products ÷ Total Products) × 100&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, if a machine is available 90% of the time, runs at 95% of its ideal speed, and 98% of products are defect-free, your OEE would be: 0.90 × 0.95 × 0.98 = 83.7%&lt;/p&gt;
&lt;h2 id=&quot;planning-your-oee-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#planning-your-oee-dashboard&quot;&gt;Planning Your OEE Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we’ve covered what OEE is, let&#39;s focus on designing a basic plan that details what are the things that we should display on our dashboard. This should consist of three parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scope of the Calculation:&lt;/strong&gt; How much data will be collected and analyzed?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Metrics:&lt;/strong&gt; Which metrics are the most important to track?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layout &amp;amp; Visualisation:&lt;/strong&gt; What visual elements will be used to present the data?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;defining-the-scope-of-oee-calculation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#defining-the-scope-of-oee-calculation&quot;&gt;Defining the Scope of OEE Calculation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first and most important step before creating the dashboard is defining the scope of the OEE calculation. The tracking level can vary based on the focus on area. Scope can vary between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Machine-level OEE:&lt;/strong&gt; Concentrates on individual machines, aiding in the identification of specific inefficiencies that impact performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line-level OEE:&lt;/strong&gt; Assesses the entire production line, offering insights into the collaboration of multiple machines and pinpointing where bottlenecks arise.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Factory-level OEE:&lt;/strong&gt; Compiles data from various production lines to provide a comprehensive overview of overall efficiency and trends.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For those building dashboards from scratch, it’s advisable to start at the machine level. This approach allows for faster time to value, as data collection can typically begin from a single point, reducing initial complexity. Once you’ve established the machine-level tracking and identified the inefficiencies, you can scale up to line-level and eventually factory-level OEE. Starting with machine-level data ensures that you can quickly uncover key insights and iteratively improve the scope and detail of your dashboard.&lt;/p&gt;
&lt;p&gt;For this series, we will be building the dashboard at the line-level. In this case, we will collect data specific to a production line and perform the OEE calculation based on that data.&lt;/p&gt;
&lt;h3 id=&quot;key-metrics-and-insights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#key-metrics-and-insights&quot;&gt;Key Metrics and Insights&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, the dashboard will calculate OEE for a production line, presenting key metrics such as availability, performance, quality, and the overall OEE score. While the overall OEE score provides a quick snapshot of performance, it does not offer enough detail to pinpoint specific areas that need improvement.&lt;/p&gt;
&lt;p&gt;To address this, the dashboard will break down the OEE calculation at the machine level as well, enabling managers to identify underperforming machines that affect overall efficiency. Additionally, it will display recent downtime incidents, summarizing this data to uncover trends and identify potential root causes. This breakdown will provide a clearer understanding of where inefficiencies are occurring and allow for targeted corrective actions.&lt;/p&gt;
&lt;p&gt;The dashboard will also track production quality, displaying the number of acceptable versus defective parts to ensure a continued focus on quality control. Additionally, last 30-days OEE trend analysis will be included, offering insights into performance changes over time. This will help managers identify patterns, monitor improvements, and highlight areas requiring attention.&lt;/p&gt;
&lt;h3 id=&quot;dashboard-visualization-%26-ui-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#dashboard-visualization-%26-ui-design&quot;&gt;Dashboard Visualization &amp;amp; UI Design&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To ensure that insights are easy to understand and act upon, the dashboard will feature a well-structured visual layout that presents complex data in a clear and intuitive manner. After analyzing various OEE dashboards, I designed this one with a focus on clarity, usability, and actionable insights. It will include gauges for a quick OEE overview, bar charts to track downtime and production trends, tables to highlight underperforming machines and recent downtime events, and line charts to monitor efficiency patterns over time. This setup ensures managers can quickly spot problems, understand their causes, and take the necessary steps to optimize production.&lt;/p&gt;
&lt;p&gt;The following dashboard image illustrates the intended design and key objectives of our OEE dashboard. Based on the plan outlined in this part, we will build the dashboard interface in the next part of the series using simulated production and downtime data.&lt;/p&gt;
&lt;p&gt;Later, we will show how to connect real factory data, scale the dashboard across multiple production lines, and use it to enhance OEE effectively.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;OEE Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/oee-dashboard-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;OEE Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-part-1/#what-next&quot;&gt;What Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here’s &lt;a href=&quot;https://flowfuse.com/blog/2025/04/building-oee-dashboard-with-flowfuse-2/&quot;&gt;Part 2&lt;/a&gt; on the next steps to build your OEE dashboard with FlowFuse. But if you rather skip the tutorials and dive straight in, just &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;register for a FlowFuse account&lt;/a&gt; and start using our ready-made &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/oee-dashboard/&quot;&gt;OEE Dashboard Blueprint&lt;/a&gt; to optimize your operations and boost efficiency right away!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/</id>
        <title>Managing MQTT Connections at Scale in FlowFuse</title>
        <summary>Automating MQTT Configuration in FlowFuse Using Environment Variables</summary>
        <updated>2025-03-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse makes it easy to deploy Node-RED flows at scale using DevOps pipelines and device groups. However, different stages in a pipeline may need different MQTT brokers—for example, one for development and another for production. Manually configuring each stage can be time-consuming, especially when a stage has multiple remote instances (devices).&lt;/p&gt;
&lt;p&gt;This article shows how to continue using FlowFuse’s one-click deployment while ensuring that remote instances in each stage of your pipeline connect to the desired MQTT broker without manual configuration.&lt;/p&gt;
&lt;h2 id=&quot;goal-and-prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#goal-and-prerequisites&quot;&gt;Goal and Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article explains how to deploy Node-RED flows across different pipeline stages while ensuring each stage connects to its appropriate MQTT broker.&lt;/p&gt;
&lt;p&gt;To proceed, ensure that the DevOps pipeline is created with the correct stages. If a stage includes remote instances, verify that all instances are running the FlowFuse Device Agent and are connected to your team.&lt;/p&gt;
&lt;p&gt;For more information on how to create a DevOps pipeline, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;How to Build and Automate DevOps Pipelines for Node-RED Deployments&lt;/a&gt;. For instructions on how to create a device group, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/device-groups/&quot;&gt;Device Groups Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;setting-environment-variables-for-development-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#setting-environment-variables-for-development-instance&quot;&gt;Setting Environment Variables for Development Instance&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For this guide, environment variables will be the key tool to ensure each pipeline stage connects to the correct MQTT broker without manual intervention, allowing for a smooth deployment process.&lt;/p&gt;
&lt;p&gt;Since the development remote instance is where the flow will be built and tested, start by adding the necessary environment variables for its MQTT configuration. Setting these up first ensures the flow runs as expected before deploying it to other pipeline stages.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to the remote/hosted instance settings in the FlowFuse platform.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to the &lt;strong&gt;Environment&lt;/strong&gt; settings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following environment variables with the appropriate values for that specific device:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HOST&lt;/code&gt; – The MQTT broker&#39;s hostname or IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PORT&lt;/code&gt; – The port number the broker is listening on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;USERNAME&lt;/code&gt; – The authentication username for the MQTT broker.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PASSWORD&lt;/code&gt; – The authentication password for the MQTT broker.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLIENT_ID&lt;/code&gt; – A unique identifier for the device connecting to the broker.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLIENT_ID_SUFFIX&lt;/code&gt; – A suffix shared among client IDs within the broker.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TOPIC&lt;/code&gt; – The MQTT topic used for message communication.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Save Settings&lt;/strong&gt; to apply the changes and restart the device.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;configuring-mqtt-in-node-red-with-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#configuring-mqtt-in-node-red-with-environment-variables&quot;&gt;Configuring MQTT in Node-RED with Environment Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, let&#39;s explore how these environment variables can be used within Node-RED to configure the MQTT broker. Node-RED offers multiple ways to reference environment variables. Here are two primary methods to configure MQTT nodes using environment variables:&lt;/p&gt;
&lt;h3 id=&quot;1.-using-the-configuration-dialog%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#1.-using-the-configuration-dialog%3A&quot;&gt;1. Using the Configuration Dialog:&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Environment variables can be directly referenced in the MQTT node properties using the &lt;code&gt;${ENV_NAME}&lt;/code&gt; syntax as shown in the following images.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Setting up MQTT connection using environment variables.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-config-with-env.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Setting up MQTT connection using environment variables.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring MQTT node security settings using environment variables in Node-RED.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-node-security-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring MQTT node security settings using environment variables in Node-RED.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the MQTT topic in Node-RED using environment variables.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-out-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the MQTT topic in Node-RED using environment variables.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;2.-setting-values-dynamically-via-the-msg-object&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#2.-setting-values-dynamically-via-the-msg-object&quot;&gt;2. Setting Values Dynamically via the &lt;code&gt;msg&lt;/code&gt; Object&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this approach, a &lt;strong&gt;Change node&lt;/strong&gt; is used to retrieve environment variables and set the necessary MQTT configuration properties in the &lt;code&gt;msg&lt;/code&gt; object. These properties include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;msg.broker.broker&lt;/code&gt; – The MQTT broker’s URL or IP address.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.action&lt;/code&gt; – Must be set to &lt;code&gt;&amp;quot;connect&amp;quot;&lt;/code&gt; when establishing a connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.broker.force&lt;/code&gt; – Must be set to &lt;code&gt;true&lt;/code&gt; to enforce the connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.broker.port&lt;/code&gt; – The port number for the MQTT connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.broker.clientid&lt;/code&gt; – The unique client identifier for the device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.broker.username&lt;/code&gt; – The MQTT username for authentication.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.broker.password&lt;/code&gt; – The MQTT password for authentication.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg.topic&lt;/code&gt; – The MQTT topic to which the device will publish or subscribe.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While the first method (direct reference in the MQTT node) is simpler and does not require additional nodes, it has limitations. It works well when there is only a single instance in the pipeline stage. However, when multiple instances exist within the same stage, the client ID, username, password, and topics often vary from device to device. The second method provides greater flexibility by dynamically adjusting these values, ensuring each device connects with the correct credentials and configurations. This approach makes the setup scalable and adaptable, eliminating the need for manual updates during deployment.&lt;/p&gt;
&lt;p&gt;Unlike the first approach, which restricts direct combinations (e.g., string + environment variables or environment variables + environment variables), the second method enables dynamic modifications.&lt;/p&gt;
&lt;h4 id=&quot;ensuring-unique-mqtt-credentials-and-topics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#ensuring-unique-mqtt-credentials-and-topics&quot;&gt;Ensuring Unique MQTT Credentials and Topics&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;As we mentioned in the multi-device deployment scenario, each device needs to establish its own connection to the MQTT broker while maintaining unique credentials and topics. If multiple devices in the same stage use identical configurations, connection conflicts—such as client ID duplication—may occur. To avoid these issues, each device must be assigned a unique client ID, username, password for security, and topic.&lt;/p&gt;
&lt;p&gt;To ensure uniqueness, we can use the default environment variables available for each remote instance, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FF_DEVICE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF_DEVICE_ID&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When generating the client ID for the MQTT broker, the device name (&lt;code&gt;FF_DEVICE_NAME&lt;/code&gt;) can be used as the username. Since all client IDs share the same suffix, this suffix can be stored as a device-level environment variable (&lt;code&gt;CLIENT_ID_SUFFIX&lt;/code&gt;). By combining both values, we can get the client ID of the device without manual intervention.&lt;/p&gt;
&lt;p&gt;For the password, you can use the device ID (&lt;code&gt;FF_DEVICE_ID&lt;/code&gt;), which is assigned when creating the client. Alternatively, you can set a common password for all clients by defining it as a device group-level environment variable.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Using a Change node to dynamically set MQTT broker connection properties.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/CHANGE-NODE-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Using a Change node to dynamically set MQTT broker connection properties.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For topics, a combination of a string and &lt;code&gt;FF_DEVICE_NAME&lt;/code&gt; can be used to ensure uniqueness.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring MQTT topics dynamically using a Change node in Node-RED.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/CHANGE-NODE-TOPIC-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring MQTT topics dynamically using a Change node in Node-RED.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Ensure that the topic configuration is set dynamically when sending the payload, not when establishing the connection.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once you have built your flow to connect to the intended MQTT broker using environment variables, deploy it and verify that it works as expected.&lt;/p&gt;
&lt;p&gt;Also, if you need an example flow to test and explore in more detail, the following flow is provided. It demonstrates how to configure the MQTT connection dynamically using environment variables and, where needed, generate some settings by combining strings with environment variables.&lt;/p&gt;
&lt;div id=&quot;nr-flow-151&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow151 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;0301bbe611a22e6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cpu&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;msgCore&#92;&quot;:false,&#92;&quot;msgOverall&#92;&quot;:true,&#92;&quot;msgArray&#92;&quot;:false,&#92;&quot;msgTemp&#92;&quot;:false,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0c0ee596549272d4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4b8f4fec3983d558&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger every 5-second interval.&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0301bbe611a22e6d&#92;&quot;,&#92;&quot;e12765d187a7b502&#92;&quot;,&#92;&quot;43e83b87e202428b&#92;&quot;,&#92;&quot;552b49b55fbf8071&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e12765d187a7b502&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Memory&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scale&#92;&quot;:&#92;&quot;Gigabyte&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fe3d07cd9f4f1b20&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;43e83b87e202428b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Uptime&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29541f3dafd85db9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;552b49b55fbf8071&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Loadavg&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b09b1eae14fac16&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c0ee596549272d4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CPU USAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.CPU_USAGE&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;75445a62bac2e0c7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fe3d07cd9f4f1b20&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MEMORY USAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.MEMORY_USAGE&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;75445a62bac2e0c7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29541f3dafd85db9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SYSTEM UPTIME&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.UPTIME&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.uptime&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;75445a62bac2e0c7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b09b1eae14fac16&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;LOAD AVERAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.ONE_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[0]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.FIVE_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[1]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.FIFTEEN_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[2]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;75445a62bac2e0c7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;75445a62bac2e0c7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;custom&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;merged&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;useparts&#92;&quot;:false,&#92;&quot;accumulate&#92;&quot;:false,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;acf3b791d682a13d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;272ec74227a151db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dynamically Configure MQTT Connection Using Environment Variables&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;action&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;connect&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.broker&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;HOST&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.port&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;PORT&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.clientid&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;${FF_DEVICE_NAME}${Client_ID_SUFFIX}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.username&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;broker.clientid&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.password&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;FF_DEVICE_ID&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;broker.force&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;bool&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4860cc23dfca9720&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4860cc23dfca9720&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;retain&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;respTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;contentType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;correl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expiry&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;f484702903e298e7&#92;&quot;,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;acf3b791d682a13d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set payload and topic&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;factory/line2/${FF_DEVICE_NAME}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4860cc23dfca9720&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;79dfc62b4b21d20b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;aeaff62b91a987d4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger on deploy&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;272ec74227a151db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f484702903e298e7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;localhost&#92;&quot;,&#92;&quot;port&#92;&quot;:1883,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;autoConnect&#92;&quot;:false,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:4,&#92;&quot;keepalive&#92;&quot;:60,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;autoUnsubscribe&#92;&quot;:true,&#92;&quot;birthTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;birthRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;birthPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthMsg&#92;&quot;:{},&#92;&quot;closeTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;closeRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;closePayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeMsg&#92;&quot;:{},&#92;&quot;willTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;willRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;willPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willMsg&#92;&quot;:{},&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sessionExpiry&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow151.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-151&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;setting-environment-variables-for-a-device-group&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#setting-environment-variables-for-a-device-group&quot;&gt;Setting Environment Variables for a Device Group&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After confirming that your flow in the development stage remote instance works as expected and connects to the broker correctly, the next step is to add environment variables.&lt;/p&gt;
&lt;p&gt;If your target stage has only a single instance, you can set the environment variables at the instance level, as shown in the image below, and use the first method discussed earlier. This approach is straightforward and efficient for configuring a single instance using environment variables.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Setting environment variables at the instance level in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/env-vars-blur.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Setting environment variables at the instance level in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, when multiple remote instances exist within the same stage, such as in a device group, configuring them individually can be impractical, especially when most settings remain the same. To simplify this process, FlowFuse allows you to set environment variables at the device group level, and you can use the second method to make the configuration quick and easy while using remote instance default environment variables.&lt;/p&gt;
&lt;p&gt;To add the device group level environment variables follow the steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to your &lt;strong&gt;device group’s settings&lt;/strong&gt; in the FlowFuse platform.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following environment variables with the appropriate values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HOST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PORT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLIENT_ID_SUFFIX&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Save Settings&lt;/strong&gt; to apply the changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring environment variables at the device group level.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/env-settings.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring environment variables at the device group level.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With this approach, you do not need to set environment variables separately for each instance. Instead, the environment variables defined at the device group level will apply to all remote instances within the group, ensuring a consistent and efficient configuration.&lt;/p&gt;
&lt;h2 id=&quot;deploying-flow-with-stage-specific-configurations-via-devops-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#deploying-flow-with-stage-specific-configurations-via-devops-pipeline&quot;&gt;Deploying Flow with Stage-Specific Configurations via DevOps Pipeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that everything is set up, trigger the deployment pipeline for the development stage. This will push the flow and settings to the next-stage instances while preserving the existing environment variables. Before applying the new configuration, all remote instances in the target stage will restart automatically.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Deploying Node-RED flows using FlowFuse&#39;s DevOps pipeline.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devops-pipeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Deploying Node-RED flows using FlowFuse&#39;s DevOps pipeline.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If everything is configured correctly, the MQTT nodes in each remote Node-RED instance will connect to the appropriate broker configured at the device group level.&lt;/p&gt;
&lt;h2 id=&quot;monitoring-mqtt-topic-hierarchy-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#monitoring-mqtt-topic-hierarchy-with-flowfuse&quot;&gt;Monitoring MQTT Topic Hierarchy with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the Node-RED flow is deployed on all remote instances in the device group and the MQTT nodes in each instance are connected to the broker, you can monitor and manage all topics across all brokers directly in FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Monitoring MQTT topics in FlowFuse across multiple brokers.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-monitoring.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Monitoring MQTT topics in FlowFuse across multiple brokers.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Watch this short video to learn how to bring your own brokers for topic monitoring in FlowFuse: &lt;a href=&quot;https://youtube.com/shorts/-8TPXb0h0vA?si=wi3wghi4vUWlXJTZ&quot;&gt;https://youtube.com/shorts/-8TPXb0h0vA?si=wi3wghi4vUWlXJTZ&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/managing-mqtt-connections-at-scale-in-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse makes it easy to deploy Node-RED flows while ensuring each stage connects to the right MQTT broker. By using environment variables at both the instance and device group levels, you can automate MQTT configurations, reducing manual setup and ensuring consistency.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get Started Now&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/</id>
        <title>FlowFuse 2.15: Personal Node Collections, Smart Schema Suggestions and more control in DevOps Pipelines!</title>
        <summary>Start building out your own collection of private nodes and Javascript libraries for Node-RED with our new Custom Node catalogues</summary>
        <updated>2025-03-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Our three focal points for the latest release of FlowFuse have been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Collaborative Development:&lt;/strong&gt; Our new &lt;strong&gt;Custom Node Catalogues&lt;/strong&gt; provides a place for you to centralise your own private nodes and Javascript libraries for Node-RED.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full Stack Applications:&lt;/strong&gt; We&#39;ve added our new &lt;strong&gt;&amp;quot;Smart Schema Suggestions&amp;quot;&lt;/strong&gt; feature for automatically generating documentation for your MQTT Brokers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevOps:&lt;/strong&gt; We&#39;ve improved Pipelines now to let you deploy to Device Groups in the middle of a Pipeline, this is just the first step in a wider set of improvements to come for DevOps Pipelines.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-node-catalogues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#custom-node-catalogues&quot;&gt;Custom Node Catalogues&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the new &amp;quot;Custom Nodes&amp;quot; view in Team Library&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-custon-catalog.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the new &amp;quot;Custom Nodes&amp;quot; view in Team Library&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;pain-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#pain-point&quot;&gt;Pain Point&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many of our customers have very mature Node-RED setups, including large collections of their own, custom node packages that they have built. These packages range significantly in purpose, from small utility functions, to custom hardware integrations.&lt;/p&gt;
&lt;p&gt;Until now, to utilise these packages within FlowFuse, you would either need to publish to the &lt;a href=&quot;https://flows.nodered.org/search?type=node&quot;&gt;public Node-RED Community Catalogue&lt;/a&gt;, meaning all of your nodes are available to anyone in the world using Node-RED, or you had to setup and manage your own private NPM registry, which is very time consuming and requires deeper technical knowledge.&lt;/p&gt;
&lt;h3 id=&quot;now-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#now-in-flowfuse&quot;&gt;Now in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With our new update, every Team- and Enterprise-Tier Library in FlowFuse has an in-built private Node collection, ready for you to go. This means that you can push your custom node packages directly to that registry, and make it available to all of your Instances running in FlowFuse within seconds. This comes built in with full version control and all of the great update mechanisms that you already have in Node-RED.&lt;/p&gt;
&lt;p&gt;This new feature also integrates seamlessly ith our &lt;a href=&quot;https://flowfuse.com/docs/user/bill-of-materials/&quot;&gt;Bill of Materials&lt;/a&gt; view, providing you the single source of truth to all of your Instance&#39;s dependencies in one-place, making it easier to audit and manage your Node-RED instances and their dependencies.&lt;/p&gt;
&lt;h2 id=&quot;mqtt-broker-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#mqtt-broker-integration&quot;&gt;MQTT Broker Integration&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;smart-schema-suggestions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#smart-schema-suggestions&quot;&gt;Smart Schema Suggestions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;bNeTDJUZ1So&quot; params=&quot;rel=0&quot; style=&quot;margin-bottom: 12px; width: 100%; height: 400px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;We are very pleased to announce our new &amp;quot;Smart Suggestions&amp;quot; feature. When working with an MQTT Broker for live data, it can be difficult to understand the structure of the data and topics that are being used. We recently released the new &amp;quot;Hierarchy&amp;quot; view, showing the topic structure present on a Broker, and we&#39;ve now evolved that even further.&lt;/p&gt;
&lt;p&gt;With Smart Suggestions, you will be presented with proposals as to what FlowFuse &lt;em&gt;thinks&lt;/em&gt; your payload schema is, based on the data that is being published to your Broker. If you approve these suggestions, then FlowFuse wll start constructing a schema to represent the traffic on your Broker, and make that available in our new &amp;quot;Schema Documentation&amp;quot; view.&lt;/p&gt;
&lt;p&gt;This will save you days of effort in documenting your Broker, and provide a single source of truth for your schema to ensure your team is always on the same page when working with your MQTT data.&lt;/p&gt;
&lt;h3 id=&quot;searching-for-topics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#searching-for-topics&quot;&gt;Searching for Topics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A very nice, small, improvement we&#39;ve made to the Broker view too is the ability to search for topics to quickly find the topics of interest. This is a small but very useful feature, especially for those with large numbers of topics on their Broker, enabling you to find the topics of interest much faster.&lt;/p&gt;
&lt;h2 id=&quot;devops-pipelines-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#devops-pipelines-improvements&quot;&gt;DevOps Pipelines Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last year, we announced the introduction of Device Groups. For those that are not familiar with Device Groups, this feature enables users to logically group their Remote Instances so that they can be targeted in a DevOps Pipeline, facilitating streamlined and efficient deployments across your fleet of devices, rolling out a single flow to thousands of Remote Instances within seconds.&lt;/p&gt;
&lt;p&gt;Previously, you could only use a Group as the &lt;em&gt;last&lt;/em&gt; stage in a Pipeline. With this update, you can now have Groups at other stages in a pipeline. For example, you may have a group of test Remote Instances that you want to push updates to, before pushing them out to your larger group of production Instances.&lt;/p&gt;
&lt;p&gt;This improvement not only saves time but also enhances the consistency and reliability of Remote Instance management across your fleet.&lt;/p&gt;
&lt;h2 id=&quot;removing-credit-card-requirement-for-free-tier&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#removing-credit-card-requirement-for-free-tier&quot;&gt;Removing Credit Card Requirement for Free Tier&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When we recently introduced the new Free Tier for FlowFuse Cloud, we had some legacy architecture in place that meant that, whilst it was entirely free, the Free Tier still require you to put in credit card details.&lt;/p&gt;
&lt;p&gt;This is something we&#39;ve completely overhauled in the new version of FlowFuse, so now, you can just sign up and get started with building your own Remote Instances without the need for any credit card details. It was deployed to FlowFuse Cloud a week ago, and is already proving popular with new users. We can&#39;t wait to see what everyone builds on the free tier.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-dashboard-authentication-now-includes-user&#39;s-role&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#flowfuse-dashboard-authentication-now-includes-user&#39;s-role&quot;&gt;FlowFuse Dashboard Authentication Now Includes User&#39;s Role&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An enhancement to FlowFuse&#39;s underlying Node-RED launcher is the inclusion of the FlowFuse user&#39;s role in the &lt;code&gt;user&lt;/code&gt; object return by the FlowFuse User Addon. This means you can start building your own RBAC (Role Based Access Control) into your own Node-RED/Dashboard applications, without the need to define roles and access levels directly within your Node-RED flows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img style=&quot;margin: auto&quot; width=&quot;300px&quot; alt=&quot;Screenshot showing the inclusion of the user&#39;s role within Dashboard&#39;s &amp;quot;user&amp;quot; object&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-user-role.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the inclusion of the user&#39;s role within Dashboard&#39;s &amp;quot;user&amp;quot; object&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#what-else-is-new%3F&quot;&gt;What Else Is New?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.15 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.15.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/03/flowfuse-release-2-15/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/</id>
        <title>Monitoring Device Health and Performance at Scale with FlowFuse</title>
        <summary>Track and Optimize Edge Device Performance with Node-RED and FlowFuse.</summary>
        <updated>2025-02-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Edge devices are everywhere, and their numbers are skyrocketing—from 2.7 billion in 2020 to a projected 7.8 billion by 2030, according to &lt;a href=&quot;https://transformainsights.com/news/edge-computing-rapid-growth-iot#:~:text=New%20Transforma%20Insights%20reports%20covering,edge%20capabilities%20in%20IoT%20devices.&quot;&gt;various reports&lt;/a&gt;. As these devices become critical for automation and data processing, monitoring their health is essential to ensure reliability and efficiency.&lt;/p&gt;
&lt;p&gt;Tracking CPU usage, memory, and system performance helps detect potential issues early, preventing downtime and optimizing operations. In this post, we will explore how to monitor devices using Node-RED and scale this process efficiently with FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;43te5aD1RRw&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-device-health-monitoring%2C-and-why-is-it-important%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#what-is-device-health-monitoring%2C-and-why-is-it-important%3F&quot;&gt;What is Device Health Monitoring, and Why is it Important?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Edge devices power IoT and automation, handling communication and data processing. As their numbers grow, ensuring they run efficiently is crucial.&lt;/p&gt;
&lt;p&gt;Monitoring device health means tracking key metrics like CPU usage, memory, uptime, and system load. High CPU usage or low memory can slow down processes, disrupt data flow, and reduce efficiency.&lt;/p&gt;
&lt;p&gt;For example, in manufacturing, edge devices connect machines to cloud systems for real-time data. If a device fails, production can be impacted.&lt;/p&gt;
&lt;p&gt;Regular monitoring helps detect issues early, prevents downtime, and keeps devices running smoothly.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-with-monitoring-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#getting-started-with-monitoring-devices&quot;&gt;Getting Started with Monitoring Devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We will begin by monitoring a single device, such as a Raspberry Pi, collecting system data, and visualizing it using FlowFuse. Once the process is clear, we will expand it to monitor multiple devices at scale.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Running Node-RED Instance:&lt;/strong&gt; You need a running Node-RED instance on the device you want to monitor. The easiest way to set this up is with the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt;, which provides secure remote access, real-time collaboration, snapshots for quick recovery, DevOps tools, and device group management. With it, you can push updates to multiple devices with a single click.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a step-by-step installation guide, refer to the &lt;a href=&quot;https://flowfuse.com/docs/device-agent/quickstart/&quot;&gt;FlowFuse Device Agent Quickstart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven’t yet signed up for a FlowFuse account, &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Monitoring%20Device%20Health%20and%20Performance%20at%20Scale%20with%20FlowFuse&quot;&gt;sign up now&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Required Node-RED Nodes:&lt;/strong&gt; To collect system data and display it on a dashboard, install the following Node-RED nodes via the &lt;a href=&quot;https://nodered.org/docs/user-guide/editor/palette/manager&quot;&gt;Node-RED Palette Manager&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-os&lt;/code&gt;: Retrieves system information such as memory, uptime, and load.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-cpu&lt;/code&gt;: Monitors CPU usage.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;: Provides UI components for visualizing system metrics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node-red-contrib-moment&lt;/code&gt;: Formats uptime duration in a human-readable format.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;collecting-cpu-and-system-metrics-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#collecting-cpu-and-system-metrics-with-node-red&quot;&gt;Collecting CPU and System Metrics with Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that Node-RED is running on your device, it’s time to gather essential system metrics. Monitoring CPU usage, memory consumption, system uptime, and load averages helps you monitormonitor performance and spot potential issues before they become serious problems.&lt;/p&gt;
&lt;p&gt;Let’s break it down step by step.&lt;/p&gt;
&lt;h4 id=&quot;collecting-cpu-usage-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#collecting-cpu-usage-data&quot;&gt;Collecting CPU Usage Data&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To start, let’s capture CPU usage in real time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;CPU&lt;/strong&gt; node from the &amp;quot;Performance&amp;quot; category onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node and uncheck all options except &amp;quot;Send a message for overall usage.&amp;quot; This ensures you get a clear view of total CPU performance. If you need per-core metrics, you can enable the other options.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;Inject&lt;/strong&gt; node, double-click it, and set it to trigger at a suitable interval (e.g., every second, every 10 seconds, or every 30 seconds). Connect its output to the CPU node.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Debug&lt;/strong&gt; node and connect it to the output of the CPU node. This lets you view CPU data in the debug pane.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Click Deploy&lt;/strong&gt; in the top-right corner of the Node-RED editor.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your debug pane will now start showing live CPU usage data:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;An image showing the flow that gathers CPU usage data and prints it in the debug pane&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/cpu-usage.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An image showing the flow that gathers CPU usage data and prints it in the debug pane&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;monitoring-memory-usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#monitoring-memory-usage&quot;&gt;Monitoring Memory Usage&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Next, let’s track memory consumption:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a Memory node onto the canvas and double-click it.&lt;/li&gt;
&lt;li&gt;Choose the unit for memory display (e.g., gigabytes for easier readability).&lt;/li&gt;
&lt;li&gt;Connect the Memory node’s input to the Inject node’s output.&lt;/li&gt;
&lt;li&gt;Connect the Memory node’s output to the existing Debug node.&lt;/li&gt;
&lt;li&gt;Click Deploy to start monitoring.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, you will see a structured object in the debug pane containing along with cpu usage:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;An image showing the flow that gathers memory usage data and prints it in the debug pane&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/memory-usage.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An image showing the flow that gathers memory usage data and prints it in the debug pane&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;totalmem: Total available memory&lt;/li&gt;
&lt;li&gt;freemem: Free memory&lt;/li&gt;
&lt;li&gt;memusage: Current memory usage&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;tracking-system-uptime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#tracking-system-uptime&quot;&gt;Tracking System Uptime&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Monitoring uptime helps detect unexpected reboots and ensures system stability.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Uptime node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect its input to the Inject node’s output.&lt;/li&gt;
&lt;li&gt;Connect its output to the Debug node.&lt;/li&gt;
&lt;li&gt;Click Deploy to activate uptime tracking.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each time the Inject node triggers, the debug pane will display the uptime in seconds and CPU and memory usage.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;An image showing the flow that gathers system uptime data and prints it in the debug pane&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/uptime.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An image showing the flow that gathers system uptime data and prints it in the debug pane&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;analyzing-load-average&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#analyzing-load-average&quot;&gt;Analyzing Load Average&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To understand how busy your system has been over time, let’s analyze the load average:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Loadavg&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect its input to the Inject node’s output.&lt;/li&gt;
&lt;li&gt;Connect its output to the Debug node.&lt;/li&gt;
&lt;li&gt;Click Deploy to start tracking.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will give you three key metrics:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;An image showing the flow that gathers system load average data and prints it in the debug pane&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/load-avg.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1-minute load average: Immediate system load&lt;/li&gt;
&lt;li&gt;5-minute load average: Recent short-term trend&lt;/li&gt;
&lt;li&gt;15-minute load average: Long-term system trend&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If these values remain consistently high, your system may struggle under excessive demand, signaling a need for optimization or additional processing power.&lt;/p&gt;
&lt;p&gt;With these metrics in place, you have a solid foundation for real-time system monitoring.&lt;/p&gt;
&lt;h3 id=&quot;sharing-data-across-different-node-red-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#sharing-data-across-different-node-red-instances&quot;&gt;Sharing Data Across Different Node-RED Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once we have the data, we must send it to the Node-RED instance handling visualization. Keeping the dashboard separate is essential for scalability. As the number of devices increases, a dedicated instance ensures we can monitor all of them from a single, centralized dashboard. This approach also makes management more efficient.&lt;/p&gt;
&lt;p&gt;To send data between multiple Node-RED instances we can use &lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/&quot;&gt;FlowFuse&#39;s Project Nodes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before sending the data though, we combine all collected metrics into a single object for better organization and easier processing. Currently, each node sends its metrics as a separate message object. Merging them into a single object streamlines data handling and reduces message overhead.&lt;/p&gt;
&lt;p&gt;Import the following flow and deploy it in the device instance. While I am not covering the step-by-step process here, the explanation below covers what the flow includes and how it works.&lt;/p&gt;
&lt;div id=&quot;nr-flow-207&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow207 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6f655630d97bac87&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cpu&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;msgCore&#92;&quot;:false,&#92;&quot;msgOverall&#92;&quot;:true,&#92;&quot;msgArray&#92;&quot;:false,&#92;&quot;msgTemp&#92;&quot;:false,&#92;&quot;x&#92;&quot;:870,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d47b2da8024123bf&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;733dc91d94f03e49&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6f655630d97bac87&#92;&quot;,&#92;&quot;bcddc3aba82a12da&#92;&quot;,&#92;&quot;7af11ed245ddf9c3&#92;&quot;,&#92;&quot;d6d58c81cea93671&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bcddc3aba82a12da&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Memory&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scale&#92;&quot;:&#92;&quot;Gigabyte&#92;&quot;,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;03ee32ddbd80d7a2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7af11ed245ddf9c3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Uptime&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6117e013be2a11ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d6d58c81cea93671&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Loadavg&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b759167c1663eb21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d47b2da8024123bf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CPU USAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.CPU_USAGE&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7429fa970d1e3099&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;03ee32ddbd80d7a2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MEMORY USAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.MEMORY_USAGE&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7429fa970d1e3099&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6117e013be2a11ac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SYSTEM UPTIME&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.UPTIME&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$floor(payload.uptime)&#92;&#92;t&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7429fa970d1e3099&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b759167c1663eb21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;LOAD AVERAGE&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.ONE_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[0]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.FIVE_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[1]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.LOAD_AVERAGE.FIFTEEN_MIN&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.loadavg[2]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7429fa970d1e3099&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7429fa970d1e3099&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;custom&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;merged&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;useparts&#92;&quot;:false,&#92;&quot;accumulate&#92;&quot;:true,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1310,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;133d57048a7b057d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;133d57048a7b057d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1490,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8123ad61cf50e61e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8123ad61cf50e61e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;project&#92;&quot;:&#92;&quot;28a809c6-b8f3-499f-bb20-e357c292b443&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;${FF_DEVICE_NAME}&#92;&quot;,&#92;&quot;x&#92;&quot;:1670,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow207.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-207&#39;) })&lt;/script&gt;
&lt;p&gt;Let&#39;s understand the flow.&lt;/p&gt;
&lt;p&gt;In the flow above, four Change nodes are used, each connected to the output of the &lt;strong&gt;CPU&lt;/strong&gt;, &lt;strong&gt;Memory&lt;/strong&gt;, &lt;strong&gt;Uptime&lt;/strong&gt;, and &lt;strong&gt;Loadavg&lt;/strong&gt; nodes. As mentioned earlier, these nodes provide their data separately as &lt;code&gt;msg.payload&lt;/code&gt;. We use Change nodes to modify the message structure before sending the data to ensure a more structured and organized format.&lt;/p&gt;
&lt;p&gt;Next, a Join node merges the &lt;code&gt;msg.data&lt;/code&gt; objects from all Change nodes into a single data object. After that, another Change node assigns this combined object to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final combined object appears as shown in the image below:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Combined object containing system data such as CPU usage, memory usage, uptime, and load average.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/combine-object.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Combined object containing system data such as CPU usage, memory usage, uptime, and load average.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To share this data with other Node-RED instances, we use the &lt;strong&gt;Project Out&lt;/strong&gt; node, which is available exclusively on FlowFuse. It works similarly to the Node-RED Link nodes, but allows for communication between multiple Instances, and uses MQTT in the background, so also beenfits with topic hierarchies for any communications.&lt;/p&gt;
&lt;p&gt;In this Project node, we broadcast the message across all instances in the team using &lt;code&gt;${FF_DEVICE_NAME}&lt;/code&gt; as the topic—an environment variable automatically created in all FlowFuse instances.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the environment variables of Raspberry Pi devices with their values.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/env.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the environment variables of Raspberry Pi devices with their values.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Using environment variables as the topic enables the same flow to be used across multiple devices without modification, ensuring that each device utilizes its own environment variables (device name) and sends data under its respective topic.&lt;/p&gt;
&lt;h3 id=&quot;visualizing-data-with-the-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#visualizing-data-with-the-flowfuse-dashboard&quot;&gt;Visualizing Data with the FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that the data is being broadcasted, it can be used to build a simple dashboard that visualizes it with different types of charts.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Dashboard monitoring device CPU usage, memory uptime, and load average&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-monitoring-device.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard monitoring device CPU usage, memory uptime, and load average&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ensure that a separate &lt;strong&gt;Hosted Instance&lt;/strong&gt; has been created in the same Team where the hardware is registered. This instance will be used to deploy the dashboard.&lt;/p&gt;
&lt;h4 id=&quot;setting-up-the-data-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#setting-up-the-data-source&quot;&gt;Setting Up the Data Source&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project In&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and select &amp;quot;Listen for broadcast messages from&amp;quot;.&lt;/li&gt;
&lt;li&gt;Choose &amp;quot;All instances and devices&amp;quot; from the &amp;quot;Source&amp;quot; dropdown menu.&lt;/li&gt;
&lt;li&gt;Enter the device name in the topic field, ensuring it matches exactly with the &lt;code&gt;${FF_DEVICE_NAME}&lt;/code&gt; device environment variable.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;memory-usage-visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#memory-usage-visualization&quot;&gt;Memory Usage Visualization&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag two &lt;strong&gt;Change&lt;/strong&gt; nodes onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the first &lt;strong&gt;Change&lt;/strong&gt; node. Set &lt;code&gt;msg.payload&lt;/code&gt; to:
&lt;div style=&quot;position: relative&quot; id=&quot;code-container-371&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-371&quot; class=&quot;language-json&quot;&gt;payload.MEMORY_USAGE.totalmem - payload.MEMORY_USAGE.freemem&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-371&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.topic&lt;/code&gt; to &amp;quot;USED MEMORY&amp;quot; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Double-click on the second &lt;strong&gt;Change&lt;/strong&gt; node, Set &lt;code&gt;msg.payload&lt;/code&gt; to:
&lt;div style=&quot;position: relative&quot; id=&quot;code-container-382&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-382&quot; class=&quot;language-json&quot;&gt;msg.payload.MEMORY_USAGE.freemem&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-382&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.topic&lt;/code&gt; to &amp;quot;Free Memory&amp;quot; and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-chart&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the widget and create a new Group.&lt;/li&gt;
&lt;li&gt;Set the chart type to &amp;quot;Pie&amp;quot; and action to &amp;quot;Append&amp;quot;.&lt;/li&gt;
&lt;li&gt;Set X to &lt;code&gt;msg.topic&lt;/code&gt; and leave Y empty.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Connect the nodes as follows:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Project In node → Change nodes → ui-chart widget&lt;/p&gt;
&lt;h4 id=&quot;cpu-usage-visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#cpu-usage-visualization&quot;&gt;CPU Usage Visualization&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag a Change node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node. Set &lt;code&gt;msg.payload&lt;/code&gt; to:
&lt;div style=&quot;position: relative&quot; id=&quot;code-container-436&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-436&quot; class=&quot;language-json&quot;&gt;$round(payload.CPU_USAGE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-436&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Drag a ui-gauge widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the widget and create a new group.&lt;/li&gt;
&lt;li&gt;Set the height and size.&lt;/li&gt;
&lt;li&gt;Select &amp;quot;3/4 gauge&amp;quot; with a rounded style.&lt;/li&gt;
&lt;li&gt;Set the range from 0 to 100.&lt;/li&gt;
&lt;li&gt;Add three segments with colors: 0 (Green), 50 (Yellow), 80 (Red).&lt;/li&gt;
&lt;li&gt;Set the label to &amp;quot;CPU&amp;quot; and unit to %.&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Connect the nodes as follows:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Project In node → Change node → ui-gauge widget&lt;/p&gt;
&lt;h4 id=&quot;system-uptime-visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#system-uptime-visualization&quot;&gt;System Uptime Visualization&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Humanizer node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node and enter &amp;quot;UPTIME&amp;quot; in the input variable field.&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Drag a Change node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node. Set &lt;code&gt;msg.payload&lt;/code&gt; to:
&lt;div style=&quot;position: relative&quot; id=&quot;code-container-520&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-520&quot; class=&quot;language-json&quot;&gt;msg.payload.humanized&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-520&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Drag a ui-text widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and create a new group.&lt;/li&gt;
&lt;li&gt;Select the correct layout.&lt;/li&gt;
&lt;li&gt;Check the &amp;quot;Apply Styles&amp;quot; option and select the color, font, and size that best suits your needs.&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Connect the nodes as follows:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Project In node → Humanizer node → Change node → ui-text widget&lt;/p&gt;
&lt;p&gt;Below is the complete dashboard flow, which visualizes the system data we collected.&lt;/p&gt;
&lt;div id=&quot;nr-flow-208&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow208 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;018657fd6a7e4237&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 1&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;MacOS&#92;&quot;,&#92;&quot;x&#92;&quot;:80,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1335f4283b6bac10&#92;&quot;,&#92;&quot;acd675febbdadc6f&#92;&quot;,&#92;&quot;f875ddcc0de1c40f&#92;&quot;,&#92;&quot;95e3d356bd589be7&#92;&quot;,&#92;&quot;7cde186dd1601efb&#92;&quot;,&#92;&quot;6448cab78573bf39&#92;&quot;,&#92;&quot;d0e232ec780650fa&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1335f4283b6bac10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Free Memory&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.MEMORY_USAGE.freemem&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Free Memory&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;eed0837fccf2639d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;eed0837fccf2639d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;a54eed4c7110dfb5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Memory Usage&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;X - msg.topic, Series - msg.series&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;pie&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Pie&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;radial&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;xmin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xmax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bins&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;interpolation&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;acd675febbdadc6f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Used Memory&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.MEMORY_USAGE.totalmem - payload.MEMORY_USAGE.freemem&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Used Memory&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;eed0837fccf2639d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f875ddcc0de1c40f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CPU Overall Usage&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$round(payload.CPU_USAGE, 2)&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;CPU Overall Usage&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a777eb57611ddd60&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a777eb57611ddd60&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;0d1f7e47031c74c1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-34&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;rounded&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;CPU &#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:10,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;95e3d356bd589be7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;humanizer&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;input&#92;&quot;:&#92;&quot;UPTIME&#92;&quot;,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9d237ff676ad6083&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;79e5bdfa309d27ea&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3827fa7650fa2fa1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Uptime&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;col-center&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:&#92;&quot;99&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#0056d6&#92;&quot;,&#92;&quot;wrapText&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:680,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9d237ff676ad6083&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.humanized&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;79e5bdfa309d27ea&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7cde186dd1601efb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;One Minute (LOAD_AVERAGE)&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.LOAD_AVERAGE.ONE_MIN&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;One Minute&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5bf2c8c93abb5a9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6448cab78573bf39&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Five Minute (LOAD_AVERAGE)&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.LOAD_AVERAGE.FIVE_MIN&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Five Minute&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5bf2c8c93abb5a9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0e232ec780650fa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Fifteen Minute (LOAD_AVERAGE)&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.LOAD_AVERAGE.FIFTEEN_MIN&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Fifteen Minute&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5bf2c8c93abb5a9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5bf2c8c93abb5a9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;797e084100cec864&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;0c78dcb3aefb38a8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;LOAD AVERAGE&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;timestamp&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;xmin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xmax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;yAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bins&#92;&quot;:10,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;dash&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#a347e1&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;interpolation&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a54eed4c7110dfb5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Memory Usage&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d0621b8f20aee671&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;0d1f7e47031c74c1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;CPU Usage&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d0621b8f20aee671&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;3827fa7650fa2fa1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;SYSTEM UPTIME&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d0621b8f20aee671&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c78dcb3aefb38a8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Load Average&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d0621b8f20aee671&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:4,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0621b8f20aee671&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Mac OS&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;6c8450c52cafa145&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/macos&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;6c8450c52cafa145&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;headerContent&#92;&quot;:&#92;&quot;page&#92;&quot;,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;showReconnectNotification&#92;&quot;:true,&#92;&quot;notificationDisplayTime&#92;&quot;:1,&#92;&quot;showDisconnectNotification&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094CE&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow208.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-208&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;scaling-device-monitoring-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#scaling-device-monitoring-with-flowfuse&quot;&gt;Scaling Device Monitoring with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have learned how to monitor a single device, built a flow to gather system data, and created a dashboard to visualize those metrics, the real challenge arises when scaling up to thousands or even tens of thousands of devices. Manually creating a system data-gathering flow for each device would be impractical. However, FlowFuse can automate this process in less than five minutes. Let&#39;s see how.&lt;/p&gt;
&lt;h4 id=&quot;creating-device-group&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#creating-device-group&quot;&gt;Creating Device Group&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the FlowFuse platform and go to the Application where your devices are and where you want to create a group. Ensure that all the devices you want to monitor are part of this application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Showing the option to switch to &amp;quot;Device Groups&amp;quot; and the &amp;quot;Add Device Group&amp;quot; button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/option-add-device-group.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Showing the option to switch to &amp;quot;Device Groups&amp;quot; and the &amp;quot;Add Device Group&amp;quot; button.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on &amp;quot;Device Groups&amp;quot; from the top menu. Next, click on the &amp;quot;Add Device Group&amp;quot; button. In the newly opened window, enter a group name and description, then click &amp;quot;Create&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Form to Create a Device Group: Enter the group name and description &quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-group-form-create.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Form to Create a Device Group: Enter the group name and description&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click on the newly created group and then click the &amp;quot;Edit&amp;quot; button at the top-right.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the edit button to be clicked on.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-device-group.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the edit button to be clicked on.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Next, in the left-side container, you will see a list of all available devices in your application. Select the devices you want to add to the group (make sure to add only the devices that require the deployment of the flow built to gather system metrics). Click the &amp;quot;Add Devices&amp;quot; button at the top-right of that container, and then click &amp;quot;Save Changes&amp;quot;. Once done, you will see all added devices in the right-side container, confirming that they have been successfully added to the group.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Interface to select the devices that need to be added to the group, along with the &#39;Add Devices&#39; button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-group-device-adding.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Interface to select the devices that must be added to the group, along with the &#39;Add Devices&#39; button.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Showing the selected devices we chose to add, along with the &#39;Save Changes&#39; button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/save-changes-to-add-devices.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Showing the selected devices we chose to add, along with the &#39;Save Changes&#39; button.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;creating-snapshot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#creating-snapshot&quot;&gt;Creating Snapshot&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the Remote Instance on which we developed the flow to monitor performance. Switch to &amp;quot;Version History&amp;quot; by clicking on &amp;quot;Version History&amp;quot; from the top.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the Snapshots tab and create a new snapshot by clicking the &amp;quot;Create Snapshot&amp;quot; button. Enter details such as the name and description. While making the snapshot, ensure the &amp;quot;Set as Target&amp;quot; option is checked before clicking &amp;quot;Create&amp;quot;. Enabling this option sets the created snapshot as the device’s active snapshot. Later, this snapshot will be used for deployment on devices within the device group via the DevOps pipeline.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Showing the option to switch to &amp;quot;Version history&amp;quot; and the &amp;quot;Create Snapshot&amp;quot; button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/create-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Showing the option to switch to &amp;quot;Version history&amp;quot; and the &amp;quot;Create Snapshot&amp;quot; button.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;&amp;quot;Showing the form to create a snapshot and the &amp;quot;Set as Target&amp;quot; option.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-active-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Showing the form to create a snapshot and the &amp;quot;Set as Target&amp;quot; option.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you want to learn more about snapshots, you can read our article &lt;a href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/&quot;&gt;Using Snapshots for Version Control in Node-RED with FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;creating-a-devops-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#creating-a-devops-pipeline&quot;&gt;Creating a DevOps Pipeline&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the application where the devices were added and the device group was created. Switch to the &amp;quot;Pipelines&amp;quot; tab at the top, then click &amp;quot;Add Pipeline&amp;quot;. In the newly opened window, enter a pipeline name.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Add Pipeline&#39; button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-pipeline-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the &#39;Add Pipeline&#39; button.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the form to create a pipeline by entering a name.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pipeline-creation-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the form to create a pipeline by entering a name.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In the newly added pipeline, click &amp;quot;Add Stage&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the button to add a stage.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/adding-stage-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the button to add a stage.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;In the newly opened window, select &amp;quot;Remote Instance&amp;quot; as the stage type, enter a stage name, and select the device where the flow was previously built for a single device. Under &amp;quot;Action,&amp;quot; select &amp;quot;Use active snapshot&amp;quot; and click &amp;quot;Add Stage&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the form to add a stage, where a stage is being added for a Raspberry Pi remote instance.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/rpi-stage.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the form to add a stage, where a stage is being added for a Raspberry Pi remote instance.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;To add another stage, select &amp;quot;Device Group&amp;quot; as the stage type, enter a stage name, choose the previously created device group, and click &amp;quot;Add Stage.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the form to add a stage, where a stage is being added for a Device Group.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/production-with-deviec-group.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the form to add a stage, where a stage is being added for a Device Group.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Before moving further, ensure all devices are in fleet mode.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the fleet mode status of the device (disabling the developer mode option will set the device to fleet mode).&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/fleet-mode.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the fleet mode status of the device (disabling the developer mode option will set the device to fleet mode).&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Once both stages are added, click the &#39;Run Pipeline&#39; button for the first stage. Running the pipeline will deploy the active snapshot to the devices in the device group, including all settings, environment variables, and flows of that instance. Whether the device group has two devices or thousands, the deployment will be completed efficiently and quickly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To learn more about DevOps pipelines, read the article: &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;Creating and Automating DevOps Pipelines for Node-RED in Industrial Environments&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, you have the system data of all devices broadcasted on the topic and the device name. To monitor each device, go to the dashboard instance, copy the flow, and create copies for each device. Ensure that you replace the topic with the corresponding device name. Additionally, create a separate page for each device, assign them to separate groups, and correctly move all copied widgets into the appropriate groups. Alternatively, follow &lt;a href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#visualizing-data-with-the-flowfuse-dashboard&quot;&gt;these steps&lt;/a&gt; again for each device, and you will have a centralized dashboard monitoring thousands of devices live.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;43te5aD1RRw&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/monitoring-system-health-performance-scale-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Building a monitoring flow in Node-RED is simple. It allows you to track key system metrics like CPU usage, memory, and uptime with minimal effort. Its low-code Interface makes it easy to create and deploy monitoring solutions quickly.&lt;/p&gt;
&lt;p&gt;However, manually deploying this monitoring flow across 10,000 or even 100,000 devices can be a complex and time-consuming task. This is where FlowFuse makes a difference. With features like Device Groups and DevOps pipelines, you can deploy your application from a single device or hosted Node-RED instance to thousands of devices with just a single click. FlowFuse also provides powerful tools for scaling, managing, and monitoring industrial operations, making large-scale deployments more efficient and hassle-free.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/</id>
        <title>Interacting with Arduino using Node-RED</title>
        <summary>Control and Automate Arduino with Node-RED</summary>
        <updated>2025-02-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Arduino is a popular open-source platform that lets you build cool electronics projects. It’s affordable and flexible, with lots of different boards and sensors to choose from. However, unlike some other boards, Arduino doesn’t have built-in internet connectivity, which can make remote control a bit tricky. Plus, it usually requires some coding to make things work.&lt;/p&gt;
&lt;p&gt;In this guide, I’ll show you how to control and automate your Arduino remotely using Node-RED and FlowFuse, all without writing any code. We’ll use the Firmata protocol to make it easy to send commands and get data from your Arduino. By the end of this tutorial, you’ll have a simple automation setup that you can control from anywhere. Just keep in mind, the Arduino will need to be connected to the device running Node-RED!&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;FTuxOy16nwo&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, you&#39;ll need the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Arduino Board: The hardware you&#39;ll be using for this project.&lt;/li&gt;
&lt;li&gt;USB cable: To connect the Arduino to your computer.&lt;/li&gt;
&lt;li&gt;Arduino IDE: Installed and set up to program your Arduino. Download the Arduino IDE if you haven&#39;t already done so. we will be using this for initial firmata implementation, not for programming&lt;/li&gt;
&lt;li&gt;FlowFuse Account: You will need a FlowFuse instance running on the device connected to the Arduino. FlowFuse allows you to access that remote instance, build flows, create remotely available dashboards, collaborate with your team on the instance, provide robust security, and much more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-started-with-arduino-and-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#getting-started-with-arduino-and-node-red&quot;&gt;Getting Started with Arduino and Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we’ll set up Node-RED on FlowFuse and download the Firmata protocol setup on the Arduino using Arduino IDE. We will also create a flow that will control an LED on the Arduino and read input data. We will later control the LED based on object detection using an object sensor to make it more interesting. If you don’t have the sensor, don&#39;t worry— you can still follow the article. The goal of this example is to demonstrate both reading and writing operations, as well as build an automation flow that reacts to input.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-running-node-red-on-the-device-connected-to-arduino&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-1%3A-running-node-red-on-the-device-connected-to-arduino&quot;&gt;Step 1: Running Node-RED on the Device connected to Arduino&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To begin, you need to run Node-RED on the device connected to your Arduino, whether it is a Raspberry Pi, Windows, or Linux system. However, simply running Node-RED locally is not sufficient if you require remote access. Setting up a server, securing it, and ensuring accessibility can be time-consuming and complex.&lt;/p&gt;
&lt;p&gt;Using the FlowFuse device agent simplifies this process. It allows you to remotely access and manage your Node-RED instance without the need for extensive configuration or security management. This approach ensures a more efficient and secure deployment, enabling you to focus on building automation solutions.&lt;/p&gt;
&lt;p&gt;For a step-by-step guide on installing and running the FlowFuse device agent, refer to the official documentation: &lt;a href=&quot;https://flowfuse.com/docs/device-agent/quickstart/&quot;&gt;FlowFuse Device Agent Quickstart&lt;/a&gt;. By the way, we also offer a &lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/&quot;&gt;free tier&lt;/a&gt; that lets you manage up to two edge devices for free. &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Interacting%20with%20Arduino%20using%20Node-RED&quot;&gt;Sign up today&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-downloading-firmata-protocol-setup-to-arduino.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-2%3A-downloading-firmata-protocol-setup-to-arduino.&quot;&gt;Step 2: Downloading Firmata protocol setup to Arduino.&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/firmata/protocol&quot;&gt;Firmata&lt;/a&gt; is a protocol for communicating between an Arduino (and other microcontrollers) and the host computer, providing direct access to the IO pins.&lt;/p&gt;
&lt;p&gt;Now, let&#39;s download the setup to the Arduino. Before proceeding, ensure your Arduino is connected to your laptop or computer via the correct USB cable. The USB connection is essential for uploading the code (sketch) to the Arduino and will also be used by Firmata for communication later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting up Arduino IDE and Download the setup from examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Arduino IDE on your computer.&lt;/li&gt;
&lt;li&gt;Ensure you have selected the correct board and port in the Tools menu. Since I am using an Arduino Uno 3 board, I’ve selected the Arduino Uno board.&lt;/li&gt;
&lt;li&gt;Go to File → Examples → Firmata, and then click on StandardFirmata. This will open the Firmata setup code.&lt;/li&gt;
&lt;li&gt;Click the Upload button in the Arduino IDE to upload the setup to your Arduino board.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Importing Standard Firmata setup sketch from examples in Arduino IDE&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/firmata-import.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Importing Standard Firmata setup sketch from examples in Arduino IDE&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once the upload is complete, the Arduino is ready to communicate via the Firmata protocol.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-connecting-node-red-to-arduino-via-serial-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-3%3A-connecting-node-red-to-arduino-via-serial-communication&quot;&gt;Step 3: Connecting Node-RED to Arduino via Serial Communication&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, Firmata typically works over a serial connection (such as USB), enabling communication between the Arduino board and your Node-RED instance. The serial communication allows Node-RED to send commands to the Arduino and receive data from it.&lt;/p&gt;
&lt;p&gt;First, we will need to install a node that will enable communication between Node-RED and the Arduino via Firmata.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installing Arduino Node&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the main menu by clicking the three horizontal lines in the top-right corner.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Manage Palette&amp;quot; from the menu.&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Install&amp;quot; tab and type &amp;quot;node-red-node-arduino&amp;quot; in the search field.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot; next to the node name.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After installing the required node for Arduino, we will set up the flow in Node-RED to establish a connection with the Arduino.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Establishing Connection with Arduino&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag any Arduino node onto the canvas&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration window.&lt;/li&gt;
&lt;li&gt;In the new window that opens, enter the port name for your Arduino (for example, COM5 on Windows or /dev/ttyUSB0 on Linux/macOS). You can find the correct port in the Arduino IDE or your system’s device manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding the port to the Arduino node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/serial-port-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding the port to the Arduino node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click and deploy by clicking the top-right deploy button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, after a few seconds, the node will establish a connection with the Arduino board. You should see a green square below the node, indicating that the connection is successful and the status is &amp;quot;Connected.&amp;quot;&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-sending-commands-to-arduino&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-4%3A-sending-commands-to-arduino&quot;&gt;Step 4: Sending Commands to Arduino&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this section, I&#39;ll show you how to send commands to your Arduino. For this practical demonstration, we will control the default Arduino LED, which is typically connected to pin 13.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Arduino-out node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration window.&lt;/li&gt;
&lt;li&gt;Select the correct configuration (serial port) that you set up in Step 3.&lt;/li&gt;
&lt;li&gt;Next, choose the type of pin you want to interact with (e.g., digital, analog, servo, etc.). Since in this example we will be interacting with an LED, which only requires on or off commands, I’ve selected Digital (0/1).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Based on the type of data you want to send, select the appropriate pin type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Digital (0/1) – accepts 0, 1&lt;/li&gt;
&lt;li&gt;Analog (0-255) (PWM) – accepts Integer values from 0 to 255&lt;/li&gt;
&lt;li&gt;Servo (0-180) – accepts Integer values from 0 to 180&lt;/li&gt;
&lt;li&gt;String – to send a string to the Arduino&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Once you&#39;ve configured the pin type, enter the pin number (e.g., 13 for the built-in LED).&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring Arduino-out node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/control-led.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Configuring Arduino-out node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Drag two Inject nodes onto the canvas. For one Inject node, set the payload to true (to turn the LED on), and for the other, set the payload to false (to turn the LED off).&lt;/li&gt;
&lt;li&gt;Connect the output of each Inject node to the input of the Arduino-out node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, you can turn the LED on and off by clicking the inject buttons. Instead of using the inject node, you can also use the FlowFuse dashboard to build an interactive dashboard. The dashboard will allow you to control the LED directly from a web interface.&lt;/p&gt;
&lt;p&gt;Below is the flow that allows you to control the LED connected to pin 13.&lt;/p&gt;
&lt;div id=&quot;nr-flow-204&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow204 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;fbe0eb6547cbfed7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pin&#92;&quot;:&#92;&quot;13&#92;&quot;,&#92;&quot;state&#92;&quot;:&#92;&quot;OUTPUT&#92;&quot;,&#92;&quot;arduino&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;x&#92;&quot;:739.8345947265625,&#92;&quot;y&#92;&quot;:645.8272094726562,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e222d2df8c62483d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Turn LED on&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fbe0eb6547cbfed7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c82bd0280ee45b3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Turn LED off&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:680,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fbe0eb6547cbfed7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino-board&#92;&quot;,&#92;&quot;device&#92;&quot;:&#92;&quot;COM5&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow204.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-204&#39;) })&lt;/script&gt;
&lt;p&gt;If you&#39;re interested in learning how to create a dashboard, you can refer to the &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started Guide&lt;/a&gt;. It will help clarify basic dashboard concepts and guide you through building a simple dashboard interface.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-receiving-inputs-from-the-arduino&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-5%3A-receiving-inputs-from-the-arduino&quot;&gt;Step 5: Receiving Inputs from the Arduino&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this step, we’ll focus on receiving inputs from the Arduino to Node-RED. For this practical demonstration, we will use the input from the IR object detection sensor connected to the Arduino.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Arduino-in node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration window.&lt;/li&gt;
&lt;li&gt;Select the serial port to which your Arduino is connected.&lt;/li&gt;
&lt;li&gt;Based on the input type, choose the correct pin type (e.g., digital, analog). Since we are using an IR sensor, which typically provides a digital output, select the &amp;quot;Digital pin&amp;quot; type.&lt;/li&gt;
&lt;li&gt;Enter the pin number (e.g., pin 9, if your sensor is connected to pin 9 on the Arduino).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring Arduino-in node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/read-sensor-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Configuring Arduino-in node&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: You cannot use the same pin for both output and input on the Arduino simultaneously. Ensure the pin you use for input (like the IR sensor) is separate from the pin you&#39;re using for output (like the LED).&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;li&gt;Drag the Debug node onto the canvas and connect its input to the output of the Arduino-in node.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, the Arduino will send the sensor input data to Node-RED. If a change is detected in the input, the Arduino will output that input, and you will see it in the debug panel.&lt;/p&gt;
&lt;p&gt;Below, I have provided the flow that reads the IR object detection sensor data connected to pin 9, in case you need it.&lt;/p&gt;
&lt;div id=&quot;nr-flow-205&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow205 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2b871fb5d0923355&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Sensor Data&#92;&quot;,&#92;&quot;pin&#92;&quot;:&#92;&quot;9&#92;&quot;,&#92;&quot;state&#92;&quot;:&#92;&quot;INPUT&#92;&quot;,&#92;&quot;arduino&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e3e52e51a2e4e058&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e3e52e51a2e4e058&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino-board&#92;&quot;,&#92;&quot;device&#92;&quot;:&#92;&quot;COM5&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow205.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-205&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;step-6%3A-creating-an-automation-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#step-6%3A-creating-an-automation-flow&quot;&gt;Step 6: Creating an Automation Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you&#39;ve learned how to send commands and read inputs from the Arduino, let’s move on to creating an automation flow. This section aims to show you how to program the Arduino without writing a single line of code—using only Node-RED.&lt;/p&gt;
&lt;p&gt;The idea is to trigger an action, such as turning on an LED, when the sensor detects an object.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a Switch node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the Switch node to open its configuration window and add the following conditions:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;msg.payload == 1&lt;/li&gt;
&lt;li&gt;msg.payload == 0&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click Done to save the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding conditions in the Switch node to check if the object is detected or not.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/switch.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding conditions in the Switch node to check if the object is detected or not.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Connect the Switch node&#39;s input to the Arduino-in node&#39;s output.&lt;/li&gt;
&lt;li&gt;Next, drag two Change nodes onto the canvas. Set the payload to false for the first Change node and true for the second Change node.&lt;/li&gt;
&lt;li&gt;Connect the first output of the Switch node to the input of the first Change node, and the second output of the Switch node to the input of the second Change node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since IR object detection sensors output a LOW (0) signal when an object is detected and a HIGH (1) signal when no object is detected, this flow will turn the LED on when an object is detected (when msg.payload is equal to 0) and turn the LED off  object is not detected (when msg.payload is equal to 1).&lt;/p&gt;
&lt;p&gt;Below, I have provided the complete flow of how we read the IR object detection sensor data and control the LED in response to the input. I have also included a video demo.&lt;/p&gt;
&lt;div id=&quot;nr-flow-206&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow206 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2b871fb5d0923355&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Sensor Data&#92;&quot;,&#92;&quot;pin&#92;&quot;:&#92;&quot;9&#92;&quot;,&#92;&quot;state&#92;&quot;:&#92;&quot;INPUT&#92;&quot;,&#92;&quot;arduino&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;x&#92;&quot;:130,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8ad3d1504ba05942&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49b04d8b6f015846&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;bool&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d6e251e983f908ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8f56a3d6ac64e87c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;bool&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d6e251e983f908ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8ad3d1504ba05942&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8f56a3d6ac64e87c&#92;&quot;],[&#92;&quot;49b04d8b6f015846&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d6e251e983f908ac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Control LED&#92;&quot;,&#92;&quot;pin&#92;&quot;:&#92;&quot;13&#92;&quot;,&#92;&quot;state&#92;&quot;:&#92;&quot;OUTPUT&#92;&quot;,&#92;&quot;arduino&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7663aaf.47194&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;arduino-board&#92;&quot;,&#92;&quot;device&#92;&quot;:&#92;&quot;COM5&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow206.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-206&#39;) })&lt;/script&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;FTuxOy16nwo&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/interacting-with-arduino-using-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this tutorial, you’ve learned how to connect your Arduino to Node-RED and control it using the Firmata protocol. We started by turning an LED on and off, reading sensor data, and building a flow to automate actions based on input from an IR sensor.&lt;/p&gt;
&lt;p&gt;This approach is so powerful that you don’t need to write any code; FlowFuse lets you create automation flows with just a few clicks. You can quickly expand this setup to include more sensors, devices, and dashboards to build your IoT projects.&lt;/p&gt;
&lt;p&gt;It’s a simple yet powerful way to interact with your Arduino, with endless possibilities. Enjoy exploring and building!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/</id>
        <title>FlowFuse 2.14: Announcing Third-Party Broker Integration, UNS Schemas, Enhanced Auth on Remote Instances and more!</title>
        <summary>A huge wave of new features in FlowFuse elevates your MQTT experience as well as providing improved Remote Instances security and version control too</summary>
        <updated>2025-02-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release is full of highlights, which we’ll break down into two key areas - the &lt;strong&gt;FlowFuse MQTT Experience&lt;/strong&gt; and &lt;strong&gt;Remote Instances&lt;/strong&gt; - so you can better digest all of the great new functionality introduced in FlowFuse 2.14.&lt;/p&gt;
&lt;h2 id=&quot;mqtt-experience-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#mqtt-experience-in-flowfuse&quot;&gt;MQTT Experience in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;October we announced the FlowFuse MQTT Broker&lt;/a&gt;, included in our Starter, Team, and Enterprise tiers. It lets you setup your own secure clients to begin publishing and subscribing to your own topics, and building out your full event-driven applications.&lt;/p&gt;
&lt;p&gt;We see the MQTT experience and Node-RED experience regularly paired together, and so it&#39;s one of our missions at FlowFuse to provide the best developer experience for building out your event-driven applications when these two elements are in play.&lt;/p&gt;
&lt;h3 id=&quot;third-party-broker-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#third-party-broker-integration&quot;&gt;Third Party Broker Integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whilst the Team Broker is a great addition, we are aware that many of our customers already have their own existing MQTT brokers and infrastructure, so what does FlowFuse bring to the table for them?&lt;/p&gt;
&lt;p&gt;With this new release, it is now possible for you to connect your external brokers to FlowFuse. With that, you&#39;ll get access to the same great features to help you gain a clear understanding of the activity on your broker, and the structure of the data and topics that are being used.&lt;/p&gt;
&lt;h3 id=&quot;schema-generation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#schema-generation&quot;&gt;Schema Generation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A pain point we&#39;ve seen for many customers is collaboration around a single UNS, or MQTT Broker. There is limited (if any) documentation, and to create that, especially at industrial scale, would be a monstrous and time-consuming task. With that in mind, FlowFuse now offers &lt;strong&gt;automated schema generation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;FlowFuse now generates a schema for your MQTT Broker&#39;s topic hierarchy, whether you&#39;re using the in-built FlowFuse Team Broker, or integrating your own, without you needing to do anything. The schema is generated using the industry-standard, open-sourced, &lt;a href=&quot;https://www.asyncapi.com/&quot;&gt;AsyncAPI&lt;/a&gt;, and is clearly presented to you in the FlowFuse UI in two formats.&lt;/p&gt;
&lt;h4 id=&quot;topic-hierarchy-editor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#topic-hierarchy-editor&quot;&gt;Topic Hierarchy Editor&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first view lives within the FlowFuse UI that you&#39;re familiar with, will display your interactive topic hierarchy which you can explore, and is predominantly the &amp;quot;edit&amp;quot; and &amp;quot;review&amp;quot; view of your hierarchy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Topic Hierarchy view for a given Broker in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-topic-hierarchy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Topic Hierarchy view for a given Broker in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For each topic, you can define descriptions so that team members and anyone interacting with your broker can get a clear understanding of how to get the most out of the hierarchy and associated data.&lt;/p&gt;
&lt;p&gt;We have also hopped the first piece of our Smart Suggestions, which is an agent that runs and works out the structure of the payloads to each of your topics. Right now, this is shown in the UI under &amp;quot;Detected Schema&amp;quot;, but we have bigger plans here, that hopefully you&#39;ll be seeing more of in the very near future.&lt;/p&gt;
&lt;h4 id=&quot;personalized-uns-documentation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#personalized-uns-documentation&quot;&gt;Personalized UNS Documentation&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The second view is focussed on clarity, and collaboration.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the new &amp;quot;Schema Documentation&amp;quot; view provided for brokers on FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-topic-docs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the new &amp;quot;Schema Documentation&amp;quot; view provided for brokers on FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A big challenge with the Unified Namespace, and wider MQTT too, can be the lack of centralized structure and information around the topics and payloads that are being used. This can make it difficult to understand what is being published and subscribed to, and can make it hard to onboard new projects, team members or partners.&lt;/p&gt;
&lt;p&gt;That is why we have built in a new &amp;quot;Schema Documentation&amp;quot; view, available for both the in-built FlowFuse Broker, and any third-party broker that you choose to connect.&lt;/p&gt;
&lt;p&gt;This view is built from the automated topic hierarchy, manually added topic descriptions and will soon feature payload schema information from our upcoming Smart Schemas.&lt;/p&gt;
&lt;h2 id=&quot;remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#remote-instances&quot;&gt;Remote Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This release sees two new major features coming to Remote Instances (previously known as &amp;quot;Devices&amp;quot;).&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-authentication-now-supported&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#flowfuse-authentication-now-supported&quot;&gt;FlowFuse Authentication now Supported&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can now secure your Remote Instances with FlowFuse Authentication.&lt;/p&gt;
&lt;p&gt;This means that you can now use the same credentials you use to log into FlowFuse, to authenticate any HTTP endpoints, such as the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt;, on your Remote Instances. This also unlocks features like &lt;a href=&quot;https://dashboard.flowfuse.com/user/multi-tenancy.html&quot;&gt;Multi-Tenant Dashboards&lt;/a&gt; that can run on your own hardware at the Edge.&lt;/p&gt;
&lt;p&gt;Please note that this does require that your hardware has a connection to FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;version-history-for-remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#version-history-for-remote-instances&quot;&gt;Version History for Remote Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the new &amp;quot;Version History&amp;quot; timeline view available for Remote Instances&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-timeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the new &amp;quot;Version History&amp;quot; timeline view available for Remote Instances&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This release brings another great update for Remote Instances: the &amp;quot;Timeline&amp;quot; view has been rolled out to provide you a clear picture of everything that has been running on your Remote Instance.&lt;/p&gt;
&lt;p&gt;Here you will be able to see every time flows were deployed (for example from within &lt;a href=&quot;https://flowfuse.com/docs/device-agent/quickstart/#developer-mode&quot;&gt;Developer Mode&lt;/a&gt;), when settings have updated, &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/&quot;&gt;Snapshots&lt;/a&gt; have been created, or new flows have been deployed via a &lt;a href=&quot;https://flowfuse.com/docs/user/devops-pipelines/&quot;&gt;DevOps Pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#what-else-is-new%3F&quot;&gt;What Else Is New?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.13 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.14.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/flowfuse-release-2-14/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/02/node-red-academy-announcement/</id>
        <title>Announcing Node-RED Academy!</title>
        <summary>The new Node-RED Academy enables you to learn Node-RED, increase your expertise, and demonstrate your knowledge with shareable certificates.</summary>
        <updated>2025-02-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/02/node-red-academy-announcement/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;Node-RED Academy&lt;/a&gt; provides Node-RED courses both for experts, who want to grow their knowledge, and for beginners, who are just learning the ropes. Get formal certification in Node-RED by completing courses and share certificates on LinkedIn to demonstrate your Node-RED learning accomplishments.&lt;/p&gt;
&lt;h2 id=&quot;what-is-node-red-academy%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/node-red-academy-announcement/#what-is-node-red-academy%3F&quot;&gt;What is Node-RED Academy?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED Academy is a brand new learning portal for Node-RED. Whether you’re a complete beginner to Node-RED or have been building applications for years, Node-RED Academy courses will take your expertise to the next level, and provide you with formal certification that are evidence of your Node-RED knowledge and skills.&lt;/p&gt;
&lt;h2 id=&quot;can-i-earn-a-credential%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/node-red-academy-announcement/#can-i-earn-a-credential%3F&quot;&gt;Can I Earn a Credential?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All courses completed through Node-RED Academy provide a formal certification upon successful course completion. You can share this certificate on LinkedIn, add it to your CV or show it off anywhere else you like.&lt;/p&gt;
&lt;p&gt;The credential will be evidence of your Node-RED knowledge and abilities, and will be a great way to demonstrate your expertise to potential employers or clients.&lt;/p&gt;
&lt;h2 id=&quot;what-courses-are-included%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/node-red-academy-announcement/#what-courses-are-included%3F&quot;&gt;What Courses are Included?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our first course, The &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;Node-RED Fundamentals&lt;/a&gt;, takes about 90 minutes to complete, is free and available now. &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;Check it out!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Node-RED Fundamentals course in progress&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/academy-screenshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Node-RED Fundamentals course in progress&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We also have plans for the following courses to follow in the future:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node-RED Advanced&lt;/li&gt;
&lt;li&gt;Building Applications with Node-RED&lt;/li&gt;
&lt;li&gt;Node-RED for Industry&lt;/li&gt;
&lt;li&gt;Node-RED for Teams&lt;/li&gt;
&lt;li&gt;FlowFuse Fundamentals&lt;/li&gt;
&lt;li&gt;FlowFuse for Teams&lt;/li&gt;
&lt;li&gt;FlowFuse Advanced&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list will likely grow beyond this too. We will be evolving our courses based on feedback and ideas from the community too!&lt;/p&gt;
&lt;h2 id=&quot;who%E2%80%99s-behind-the-node-red-academy%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/node-red-academy-announcement/#who%E2%80%99s-behind-the-node-red-academy%3F&quot;&gt;Who’s behind the Node-RED Academy?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many great resources for Node-RED education out there, but the Node-RED Academy has been curated by the authors and developers behind Node-RED and covers everything you&#39;ll need to know from building your first flow to integrating with industrial hardware.&lt;/p&gt;
&lt;p&gt;FlowFuse is an enterprise-grade industrial data platform that enables engineers to build, manage, scale, and secure their Node-RED solutions for digitalizing processes and operations. You can sign up for free &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;here&lt;/a&gt; to give it a go.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-get-started%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/02/node-red-academy-announcement/#how-do-i-get-started%3F&quot;&gt;How Do I Get Started?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Head to &lt;a href=&quot;https://node-red-academy.learnworlds.com/&quot;&gt;Node-RED Academy&lt;/a&gt; and sign up for free.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Node-RED Academy home page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/academy-home-page.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Node-RED Academy home page&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/</id>
        <title>Designing a Clear Topic Structure for Your UNS</title>
        <summary>Why Topic Structuring is Key to Scaling and Optimizing Your UNS</summary>
        <updated>2025-01-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Topic structuring is not just a technical concern when building a high-performance Unified Namespace (UNS) for manufacturing environments; it&#39;s a strategic design choice that can determine the system&#39;s scalability, efficiency, and overall effectiveness.&lt;/p&gt;
&lt;p&gt;A well-structured topic hierarchy is critical in manufacturing, where vast amounts of data flow from sensors, machines, and systems. By organizing your topics correctly, you can streamline data flow, simplify scaling, and make your system more manageable as your operations grow.&lt;/p&gt;
&lt;p&gt;In this post, we&#39;ll explore the significance of topic structuring for your UNS, outline why it&#39;s essential for scalability and performance, and share best practices for designing a robust topic hierarchy that can evolve alongside your business.&lt;/p&gt;
&lt;h2 id=&quot;why-topic-structuring-is-crucial-for-your-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/#why-topic-structuring-is-crucial-for-your-uns&quot;&gt;Why Topic Structuring is Crucial for Your UNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When building a UNS for manufacturing environments, &lt;a href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/&quot;&gt;MQTT&lt;/a&gt; is one of the most popular and preferred choices due to its lightweight, efficient, and scalable design. MQTT’s publish-subscribe model is perfect for handling the real-time, high-volume data flow in factories, where machines, sensors, and devices constantly generate information. However, while MQTT is a powerful tool, how you structure your topics plays a pivotal role in ensuring that your UNS is scalable and efficient.&lt;/p&gt;
&lt;p&gt;Manufacturing operations often experience rapid growth. The sheer number of sensors, machines, and production lines increases over time, and so does the complexity of the data. MQTT topics are hierarchical, which means they follow a tree-like structure with levels separated by a forward slash (/). This hierarchical structure can mirror the physical layout of your factory floor, providing a logical, scalable framework for your data.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/factory/line1/machine1/temperature&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This topic structure indicates that the data comes from machine1 on line1 of your factory, specifically from a temperature sensor. The structure is intuitive because it directly reflects the factory’s layout.
Adding more machines, sensors, or production lines is straightforward as your factory grows.&lt;/p&gt;
&lt;p&gt;For instance, as your factory adds a second production line, you can add topics like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/factory/line2/machine1/temperature&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/factory/line2/machine1/vibration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/factory/line2/machine2/temperature&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This hierarchical system scales seamlessly as you add more machines, sensors, and production lines without creating unnecessary complexity.&lt;/p&gt;
&lt;p&gt;A well-structured topic hierarchy improves the performance of both the network and edge devices. When monitoring or data analysis systems subscribe to topics, they can choose the data they need. This means they are not overwhelmed by unnecessary traffic, which could otherwise strain network bandwidth and device processing power.&lt;/p&gt;
&lt;p&gt;For example, imagine a maintenance team only needs to monitor the temperature of machines in line 1. With a clean topic structure, they can subscribe to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/factory/line1/machine1/temperature &lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/factory/line1/machine2/temperature&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By filtering the data, they avoid receiving irrelevant data, such as vibration readings from other machines or temperatures from machines on different production lines. This reduces network load, ensures more responsive performance, and prevents overloads on edge devices.&lt;/p&gt;
&lt;p&gt;A well-organized topic structure makes maintenance and troubleshooting much more efficient. When equipment malfunctions or a sensor starts reporting erroneous data in a smart factory, the ability to pinpoint the issue quickly is crucial. With a hierarchical topic system, you can easily trace the problem to a specific machine, sensor, or production line.&lt;/p&gt;
&lt;p&gt;For instance, imagine a temperature sensor on machine 3 in line 2 reporting abnormal values. A topic like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/factory/line2/machine3/temperature&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Immediately indicates the affected machine and production line. This clarity lets your team act quickly, reducing downtime and improving system reliability.&lt;/p&gt;
&lt;p&gt;Without a clear topic structure, identifying and diagnosing problems can become time-consuming, leading to extended downtime and inefficiencies.&lt;/p&gt;
&lt;p&gt;As new equipment, sensors, or production lines are added to the factory, a well-structured topic system helps onboard new engineers, technicians, and operators easily. A clear hierarchy provides a visual map of the system, making it easier for new users to understand the architecture and begin working with it quickly.&lt;/p&gt;
&lt;h2 id=&quot;designing-a-topic-structure-for-your-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/#designing-a-topic-structure-for-your-uns&quot;&gt;Designing a Topic Structure for Your UNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start collecting data in your UNS, it’s essential to design your topic structure. While it might seem like a small step, it’s the foundation of your system. Taking the time to plan will save you significant time and effort down the road. More importantly, it gives you a clear, high-level view of your entire factory, which is crucial for scaling effectively.&lt;/p&gt;
&lt;p&gt;First, think about the key components of your factory. For example, you might have different plants or production lines in a manufacturing setting. There will be machines or devices within each production line that produce data. Then, you’ll have various data points coming from sensors on these machines, such as temperature, humidity, or pressure.&lt;/p&gt;
&lt;p&gt;By organizing your topics around these components, you’re setting up a structure that’s easy to scale.&lt;/p&gt;
&lt;p&gt;Next, remember that MQTT topics are hierarchical, so think of them like a tree. At the top of the tree, you’ll have the broadest categories (like plants or regions). As you go down, you’ll get more specific, with production lines, machines, and then individual data points like sensor readings. The key is to keep things logical so that you can locate the data you need quickly. This organization lets you promptly expand your system later by adding new plants, lines, or machines without disrupting the entire structure.&lt;/p&gt;
&lt;p&gt;The concept of structuring topics logically and hierarchically draws from a well-known framework in manufacturing: ISA-95. ISA-95 is a standard that defines a hierarchical model for organizing and managing manufacturing systems. It divides operations from the company level to individual machines, providing a clear structure for system management.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;ISA-95 Equipment Hierarchy Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/isa-95-equipement-model.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;ISA-95 Equipment Hierarchy Model&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here’s a brief breakdown of the ISA-95 levels and how they can be translated to MQTT topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 0 – Physical Devices and Control&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where the physical data originates: sensors, actuators, and devices directly interacting with machinery and production lines. These are typically represented as devices in your MQTT topic structure.&lt;/p&gt;
&lt;p&gt;Example Topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/machineB/sensor/temperature&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/machineB/sensor/pressure&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine2/machineC/sensor/humidity&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this level, you&#39;re dealing with specific machines and sensors. The topic name clearly defines the device type (e.g., &amp;quot;sensor&amp;quot;) and the type of data it generates (e.g., &amp;quot;temperature&amp;quot;). This structure makes tracking sensor data easy for each machine or production line.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 1 – Control Devices and Systems&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This level represents the control systems that operate the machinery and manage the data flow. These systems include PLCs, SCADA systems, or other control devices that manage real-time operations.&lt;/p&gt;
&lt;p&gt;Example Topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/machineB/PLC/status&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/machineB/PLC/mode&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine2/machineC/SCADA/alerts&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Topics at this level might focus on the status and control functions of the machines. Separating control systems like PLCs or SCADA ensures that operational data (e.g., machine modes or alerts) is distinct from raw sensor data. This approach ensures that each system component can be monitored and managed independently.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 2 – Monitoring and Supervisory Control&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this level, systems monitor and manage operations. They might include higher-level systems that oversee the production lines, collect data from multiple PLCs, and trigger alerts or analyses based on predefined criteria.&lt;/p&gt;
&lt;p&gt;Example Topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/supervisor/alerts&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/supervisor/performance&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine2/supervisor/utilization&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, you might aggregate data from several control devices (like PLCs) and provide higher-level insight into the overall system. For example, a &amp;quot;performance&amp;quot; topic could aggregate sensor data to monitor the efficiency of a production line, while &amp;quot;alerts&amp;quot; might be used for system-wide warnings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 3 – Manufacturing Operations Management&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This level encompasses managing the overall production process, such as scheduling, production orders, and resource management. This is often where MES (Manufacturing Execution Systems) comes into play.&lt;/p&gt;
&lt;p&gt;Example Topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine1/MES/productionOrder&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantA/productionLine2/MES/scheduling&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/plantB/productionLine1/MES/inventoryStatus&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The data becomes more abstract at this level as you deal with business logic, production orders, and scheduling systems. For example, the &amp;quot;productionOrder&amp;quot; topic could track orders for specific products, while &amp;quot;inventoryStatus&amp;quot; could provide data on material availability for each production line.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 4 – Enterprise Resource Planning (ERP)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The highest level in the ISA-95 hierarchy is focused on enterprise-wide resource planning, financials, and decision-making processes. ERP systems integrate with manufacturing systems to provide broader business insights.&lt;/p&gt;
&lt;p&gt;Example Topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/enterprise/ERP/inventory/overview&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/enterprise/ERP/sales/orders&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/enterprise/ERP/production/metrics&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the ERP level, topics reflect cross-plant business data like inventory, order management, or performance metrics. These are less granular than lower levels and provide decision-makers with high-level insights into the health of the overall business.&lt;/p&gt;
&lt;h2 id=&quot;best-practices-for-managing-your-topic-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/#best-practices-for-managing-your-topic-structure&quot;&gt;Best Practices for Managing Your Topic Structure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As your UNS scales, following some essential best practices will ensure your topic structure remains efficient, secure, and easy to manage.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Maintain Clear Documentation:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First and foremost, maintaining clear documentation is key. A well-documented topic hierarchy is a reference point for everyone involved in the system—from developers and engineers to system administrators. This documentation should outline the naming conventions, the purpose of each topic, and how new issues should be added. Without it, there&#39;s a risk of inconsistency creeping into your system, especially as new data streams and devices are introduced. An apparent, organized reference ensures your team can efficiently navigate and expand the system without confusion.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Ensuring Consistency in Naming and Structure:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using clear, descriptive names for each topic and sticking to a consistent naming pattern across your system is essential for long-term success. A well-defined naming convention ensures that everyone involved—whether developers, engineers, or system administrators—can easily understand the purpose of each topic. Navigating your UNS becomes intuitive when topics are consistently named, and troubleshooting issues is much easier.&lt;/p&gt;
&lt;p&gt;For instance, avoid vague or overly generic names like &lt;code&gt;/sensor1/data&lt;/code&gt;, which don’t offer much context. Instead, adopt more descriptive, hierarchical names that reflect the actual source and nature of the data, such as &lt;code&gt;/plantA/productionLine1/machineB/temperature&lt;/code&gt;. A consistent structure not only enhances system readability but also ensures scalability.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Keep Topic Names Simple and Avoid Special Characters:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While it’s essential to have descriptive topic names, they should also be simple and easy to use. Long topic names can make working with your UNS quickly and efficiently harder. Also, avoid using spaces or special characters, which might cause compatibility issues with some MQTT brokers or clients.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Perform Regular Topic Cleanup and Expiration:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next, don’t overlook the importance of topic cleanup and expiration. Over time, unused or obsolete topics can accumulate, adding unnecessary complexity and overhead to the system. Left unchecked, these stale topics can lead to unwanted confusion. It’s important to regularly audit the issues in your UNS, archiving or removing those no longer needed. While some MQTT systems support automatic topic expiration, implementing manual checks as part of your routine system maintenance is still a good practice. You’ll also want to manage the use of retained messages carefully. While they can help provide the latest state to new subscribers, overuse or misuse can lead to outdated information circulating across the system. Be mindful about which topics should retain data and ensure they are updated or cleaned up regularly.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Implement Robust Access Control:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Access control is essential in managing a large-scale UNS. The hierarchical structure of MQTT topics naturally supports role-based access control (RBAC), allowing you to assign permissions based on topics. This ensures users and devices only access the data they need.&lt;/p&gt;
&lt;p&gt;For example, engineers might only need access to machine-level sensor data, while plant managers require broader visibility into performance metrics across production lines. Additionally, you can restrict which devices can publish data on specific topics, ensuring only authorized systems send critical updates.&lt;/p&gt;
&lt;p&gt;By defining clear access rules, you enhance security, maintain data integrity, and ensure that your UNS can scale efficiently as your organization grows.&lt;/p&gt;
&lt;h2 id=&quot;effortless-mqtt-and-topic-management-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/designing-topic-hierarchy-for-your-uns/#effortless-mqtt-and-topic-management-with-flowfuse&quot;&gt;Effortless MQTT and Topic Management with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is more than just a low-code platform; it’s a game-changer for building and scaling your UNS. By seamlessly integrating MQTT, FlowFuse empowers you to connect, manage, and scale your industrial data systems efficiently.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s built-in MQTT broker gives you high-performance data handling without additional infrastructure overhead. The platform also features an interface for managing MQTT clients with access control for topics and an intuitive Topic Hierarchy View, which provides a real-time, visual representation of your entire MQTT topic structure. This makes organizing, monitoring, and managing your topics easy, ensuring clarity and consistency as your system grows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing FlowFuse topic hierarchy interface for UNS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-mqtt-topic-hierarchy-monitoring.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing FlowFuse topic hierarchy interface for UNS&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What truly stands out is FlowFuse&#39;s ability to handle both legacy and modern industrial protocols, effortlessly bridging the gap between old and new systems. Whether adding new devices, integrating data streams, or scaling to thousands of devices, FlowFuse gives you the flexibility, scalability, and security you need to optimize your UNS at every step.&lt;/p&gt;
&lt;p&gt;FlowFuse doesn’t just help you manage topics—it streamlines collaboration, enhances system performance, and accelerates your journey toward a fully integrated, future-proof UNS.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/</id>
        <title>How to Choose the Right IIoT Device Management Software for Your Business</title>
        <summary>Key Features and Considerations for Effective IIoT Device Management</summary>
        <updated>2025-01-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;With more devices being connected across industrial environments, managing them can get pretty overwhelming. The right IIoT device management software can help you stay on top of things—keeping everything secure, up-to-date, and running smoothly. But with so many options out there, how do you figure out which one’s best for your business?&lt;/p&gt;
&lt;p&gt;This guide will take you through the key features and considerations to keep in mind when choosing IIoT device management software. Whether you’re just starting out with IIoT or looking to improve your current setup, we’ve got some helpful insights to point you in the right direction.&lt;/p&gt;
&lt;h3 id=&quot;1.-vendor-reputation-and-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#1.-vendor-reputation-and-support&quot;&gt;1. Vendor Reputation and Support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to IIoT systems, the right vendor can make all the difference. After all, your device management platform will be at the heart of your manufacturing operations, and any hiccups can result in costly downtime. That&#39;s why choosing a vendor with a solid reputation is non-negotiable. Start by researching companies that have a proven track record in industrial environments. Look for vendors who not only understand the technical side of IIoT but also know how to support real-world use cases in manufacturing. Customer reviews and case studies can provide valuable insight into their reliability, service quality, and expertise.&lt;/p&gt;
&lt;p&gt;One of the most important factors to consider is the availability of customer support. Your platform should be backed by a responsive, accessible support team, especially when things go wrong. In high-pressure situations, like production delays or equipment failures, 24/7 support can be a game-changer. You don’t want to be waiting hours for help when every minute counts. Look for vendors that offer clear, well-documented resources along with robust, round-the-clock support to guide you through troubleshooting and problem resolution.&lt;/p&gt;
&lt;h3 id=&quot;2.-remote-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#2.-remote-access&quot;&gt;2. Remote Access&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The best device management software should make it easy to manage devices from anywhere. Remote access is crucial, especially for businesses with devices spread across different locations or those that operate 24/7. With remote access, your team can monitor device performance, troubleshoot issues, and push updates without needing to be on-site. This flexibility reduces downtime and ensures everything stays operational, no matter where you are.&lt;/p&gt;
&lt;p&gt;For example, imagine you have a factory in a remote area and a critical device experiences a malfunction. Without remote access, you would need to send a technician on-site, which could involve travel time, accommodation, and delays in getting the machine back up and running. This can be costly—not just in terms of money but also in lost production time. With remote access, however, your team can instantly diagnose the issue, push an update, or even resolve the problem without the need for a costly site visit. This means less downtime, faster resolutions, and a more efficient operation overall.&lt;/p&gt;
&lt;h3 id=&quot;3.-automated-monitoring-and-alerts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#3.-automated-monitoring-and-alerts&quot;&gt;3. Automated Monitoring and Alerts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In manufacturing, keeping a constant watch on device health is crucial to avoid unexpected failures that could lead to costly downtime. The ideal device management platform should automatically track key performance metrics—such as device crashes, CPU usage, and more. By continuously monitoring these metrics, the platform can quickly identify any abnormalities and alert your team before small issues escalate into major problems.&lt;/p&gt;
&lt;p&gt;For example, imagine a device on the factory floor experiences high CPU usage and is about to crash. An automated alert would immediately notify your team, allowing them to take swift action and address the issue before it causes a disruption. This proactive approach helps keep production running smoothly and minimizes unnecessary downtime.&lt;/p&gt;
&lt;p&gt;The platform should also allow you to set custom thresholds for specific performance metrics. This way, your team will only receive alerts for critical issues, reducing the noise from less important events. With this level of precision, responses become faster and more focused, ensuring that the most pressing concerns are addressed promptly.&lt;/p&gt;
&lt;p&gt;Automated monitoring and alerts not only save time but also increase the reliability and productivity of your IIoT ecosystem. By catching potential failures early, you can prevent unplanned downtime and ensure that your operations remain efficient and uninterrupted.&lt;/p&gt;
&lt;h3 id=&quot;4.-device-grouping-and-scalability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#4.-device-grouping-and-scalability&quot;&gt;4. Device Grouping and Scalability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As your IIoT network grows, managing each device individually can quickly become overwhelming. That&#39;s why it&#39;s essential to choose a platform that allows you to group devices by function, location, or type. For example, you could group all the devices in Production Line 1, making it easier to deploy workflows, software updates, or configurations with just a single click for all.&lt;/p&gt;
&lt;p&gt;Device grouping simplifies the management process, enabling you to update settings, deploy updates, and troubleshoot multiple devices at once. Scalability is also crucial—your platform should seamlessly accommodate new devices as your operations expand, without adding unnecessary complexity or slowing down performance.&lt;/p&gt;
&lt;p&gt;With the right platform, you can keep your IIoT network organized and scalable, ensuring that as your business grows, device management remains efficient and hassle-free.&lt;/p&gt;
&lt;h3 id=&quot;5.-wide-range-of-device-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#5.-wide-range-of-device-support&quot;&gt;5. Wide Range of Device Support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a busy manufacturing environment, you&#39;re working with a mix of devices—some on Linux, some on Windows, and others with their own custom software. The last thing you want is to have to juggle multiple platforms to manage all your devices.&lt;/p&gt;
&lt;p&gt;Find a device management system that works with all of them. A flexible platform will let you manage all your devices, regardless of their operating system, from one central dashboard. This makes your life a lot easier and keeps your operations running smoothly.&lt;/p&gt;
&lt;h3 id=&quot;6.-built-in-devops-toolset&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#6.-built-in-devops-toolset&quot;&gt;6. Built-in DevOps Toolset&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Automation is essential for boosting manufacturing efficiency. device management platforms with built-in DevOps tools integrate easily with production systems. They automate tasks like device setup, configuration, and software updates, helping reduce downtime and speed up troubleshooting.&lt;/p&gt;
&lt;p&gt;DevOps pipelines allow you to create workflows tailored to your needs, automating updates and maintenance for IIoT devices. This means your platform can push updates without interrupting production, reducing the need for manual work.&lt;/p&gt;
&lt;p&gt;With the flexibility to create custom DevOps pipelines, you can manage devices more efficiently, save time, minimize errors, and keep everything aligned with production requirements.&lt;/p&gt;
&lt;h3 id=&quot;7.-real-time-collaboration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#7.-real-time-collaboration&quot;&gt;7. Real-Time Collaboration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Managing IIoT devices often involves teams working together, sometimes from different locations. That’s why having a platform that supports real-time collaboration is so important. It allows your team to stay in sync, making it easier to troubleshoot issues or implement updates without delays.&lt;/p&gt;
&lt;p&gt;Look for a platform that lets multiple team members access and manage devices at the same time. This way, everyone can contribute to resolving problems or pushing updates without stepping on each other’s toes. Real-time collaboration helps keep things running smoothly, especially when quick responses are needed.&lt;/p&gt;
&lt;h3 id=&quot;8.-accidental-recovery-or-rollback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#8.-accidental-recovery-or-rollback&quot;&gt;8. Accidental Recovery or Rollback&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another essential feature to look for is the ability to recover from system failures or accidental misconfigurations. Accidents can happen at any time, and being able to revert to a previous stable state quickly can save you from costly downtime and operational disruptions.&lt;/p&gt;
&lt;p&gt;The ideal IIoT device management platform should include a snapshot or rollback functionality. This allows you to take snapshots of your device configurations and system state at various points in time. In the event of an issue, you can simply roll back to a previous snapshot, restoring your devices to their last known good state.&lt;/p&gt;
&lt;p&gt;This feature is especially critical in production environments where system stability is key to preventing operations interruptions. It minimizes downtime, ensures data integrity, and provides peace of mind, knowing that you can recover quickly from mistakes or technical failures.&lt;/p&gt;
&lt;h3 id=&quot;9.-system-and-audit-log-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#9.-system-and-audit-log-management&quot;&gt;9. System And Audit Log Management&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to managing IIoT devices, keeping track of what’s happening in your system is essential. A good platform will automatically log everything—device activities, errors, and user actions—so you can stay on top of things.&lt;/p&gt;
&lt;p&gt;Audit logs are especially helpful because they tell you who accessed the system, what actions were taken, and when they happened. This level of visibility makes it easier to spot any security risks or unauthorized changes early, helping you address them before they turn into bigger issues.&lt;/p&gt;
&lt;p&gt;These logs are also crucial for compliance. By maintaining a clear record of all changes, you can easily demonstrate that your system meets industry regulations and standards. This adds an extra layer of security and peace of mind, knowing that everything is being properly documented and monitored.&lt;/p&gt;
&lt;h3 id=&quot;10.-strong-security-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#10.-strong-security-features&quot;&gt;10. Strong Security Features&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to IIoT, security is a top priority, especially with sensitive production data involved. Look for a platform that offers end-to-end encryption to ensure your data stays protected as it moves between devices and the cloud.&lt;/p&gt;
&lt;p&gt;Access control is also important. A good IIoT platform will limit device access based on user roles, so only authorized personnel can view or make changes to sensitive data. This helps keep things secure by preventing unauthorized access.&lt;/p&gt;
&lt;p&gt;To stay ahead of potential security risks, the platform should include vulnerability scanning tools like SBOM (Software Bill of Materials). These tools help you track and manage any risks from third-party software, giving you peace of mind.&lt;/p&gt;
&lt;p&gt;For added protection, choose a platform that supports multi-factor authentication (MFA). MFA provides an extra layer of security in case login credentials are compromised.&lt;/p&gt;
&lt;p&gt;Finally, make sure the platform secures device-to-cloud for remote accesss connections with methods like SSH tunneling and VPNs. These help ensure that data is transmitted safely and only accessible by trusted users, no matter where your devices are located.&lt;/p&gt;
&lt;h3 id=&quot;11.-user-friendly-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#11.-user-friendly-interface&quot;&gt;11. User-Friendly Interface&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your team shouldn’t waste time struggling with a complicated platform in a busy manufacturing environment. Choose a device management platform with a simple, intuitive interface that makes monitoring devices, adjusting settings, and resolving issues quick and easy.&lt;/p&gt;
&lt;p&gt;A clean, easy-to-navigate UI allows your team to stay focused on key tasks like tracking device health and performance without unnecessary complexity. Simple controls for configuring devices, applying updates, and onboarding new devices will save time and reduce frustration.&lt;/p&gt;
&lt;h3 id=&quot;12.-cost-considerations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#12.-cost-considerations&quot;&gt;12. Cost Considerations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When selecting a device management platform, it&#39;s crucial to look beyond just the initial cost. Consider the total cost of ownership, which includes licensing fees, ongoing maintenance, training, and technical support. These factors can add up over time, so it’s important to factor them into your decision-making process.&lt;/p&gt;
&lt;p&gt;For example, a platform that charges based on the number of devices may seem affordable when you&#39;re just starting with a small network. However, as your operations scale, those costs can quickly increase. Take the time to compare different pricing models and choose the one that best fits your budget and future growth plans. This will ensure that your investment remains sustainable and supports your business over the long term.&lt;/p&gt;
&lt;h3 id=&quot;13.-integration-with-existing-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#13.-integration-with-existing-systems&quot;&gt;13. Integration with Existing Systems&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A good device management platform should make it easy for your devices to integrate with your existing systems—whether that’s your ERP, CRM, or maintenance software. This helps prevent data silos and ensures all your existing systems can work together and share data in real-time.&lt;/p&gt;
&lt;p&gt;When your devices, machines, and software are connected, it keeps important information flowing freely across your operations. This makes it simpler to track inventory, monitor device health, or manage maintenance, and it helps you make more informed decisions.&lt;/p&gt;
&lt;p&gt;The right platform should support a wide range of industrial protocols, from the latest to older systems, so everything can be included. By linking all your existing systems, you can create a single source of truth, keeping things running more smoothly and efficiently.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 3px solid rgba(173, 192, 252, 0.55); opacity: 0.3; margin-bottom: 20px;&quot; /&gt;
&lt;p&gt;So, after all’s said and done, the secret to choosing the right IIoT device management software isn’t just about checking boxes on a list. It’s about finding a solution that keeps things simple, secure, and scalable for the long haul. Look for something that lets you stay in control, whether you&#39;re managing one device or a thousand, and make sure it’s backed by solid support when you need it most. In the end, the right platform should feel less like a tool and more like a partner that grows with you. Trust me, the right fit will make your life a whole lot easier.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-%E2%80%93-the-ultimate-iiot-device-management-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/how-to-choose-right-iot-device-management-tool/#flowfuse-%E2%80%93-the-ultimate-iiot-device-management-solution&quot;&gt;FlowFuse – The Ultimate IIoT Device Management Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is an open-source industrial data platform that simplifies the management, scaling, and security of IIoT devices. Whether you&#39;re managing a handful of devices or overseeing thousands, FlowFuse &lt;a href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/&quot;&gt;consolidates everything into a single, intuitive interface&lt;/a&gt;. With seamless cross-platform support, you can control all your devices from one central hub, streamlining operations and enhancing efficiency.&lt;/p&gt;
&lt;p&gt;Built on the flexible &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; framework, FlowFuse easily integrates with a wide range of hardware, services, and APIs with over &lt;a href=&quot;https://flowfuse.com/integrations/&quot;&gt;5000 community contributed nodes&lt;/a&gt;, allowing you to tailor and scale your IIoT network to meet evolving demands. The best part? You don’t need coding knowledge to get started—Node-RED’s visual programming interface makes it easy to create custom workflows with drag-and-drop functionality. With 24/7 expert support and an active community, you&#39;ll have access to the resources you need to resolve any challenges quickly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/&quot;&gt;Security is a top priority for FlowFuse&lt;/a&gt;. With features like SSH tunneling for secure remote device access, end-to-end encryption, and multi-factor authentication, your data is protected no matter where it’s being transferred. Role-Based Access Control (RBAC) ensures that only authorized users can make critical changes, while SOC 2 compliance provides an added layer of assurance for your sensitive operations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/&quot;&gt;Real-time collaboration is built into the platform&lt;/a&gt;, enabling your team to work together on projects, monitor devices remotely, and deploy updates simultaneously—all within a secure environment. &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;Role-Based Access Control (RBAC)&lt;/a&gt; ensures that each team member has appropriate permissions based on their role. For example, admins can make critical changes, while operators can only monitor or update devices. This helps maintain control over sensitive functions while allowing your team to collaborate effectively. Together with RBAC, FlowFuse maximizes both security and productivity by ensuring the right people have access to the right tasks, at the right time.&lt;/p&gt;
&lt;p&gt;If things go awry, FlowFuse’s &lt;a href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/&quot;&gt;snapshot&lt;/a&gt; feature lets you quickly revert to a previous stable state, minimizing downtime and keeping your systems running smoothly. Advanced monitoring tools continuously track device performance, sending alerts if issues like crashes or resource overloads arise, so your team can act before problems escalate. Detailed device logs and audit trails make troubleshooting straightforward, helping you quickly pinpoint issues and maintain a secure environment.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/</id>
        <title>Why FlowFuse is the Complete Toolkit For Building UNS?</title>
        <summary>The Open-Source Solution to Build and Manage a Successful UNS</summary>
        <updated>2025-01-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Unified Namespace (UNS) is changing the way data is managed in industrial environments. It’s becoming the key to more successful and productive operations. Many organizations have already implemented it, and others are still figuring out the best approach and platform to implement it. There are so many tools out there; how do you know which one is right for your UNS? It’s a big decision, and it can be overwhelming. The good news? FlowFuse is the toolkit you’ve been looking for! It’s an all-in-one platform to build your UNS—and it’s open-source!&lt;/p&gt;
&lt;p&gt;At its core, a Unified Namespace (&lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;UNS&lt;/a&gt;) is a data architecture that centralizes all your data from devices, sensors, and systems into a single hub. It helps you make sense of everything by organizing, structuring, and standardizing your data for easy access and analysis. Instead of dealing with fragmented data silos, you get a unified, real-time view of your entire operation.&lt;/p&gt;
&lt;p&gt;Think of it as the brain of your entire operation, connecting all your business events in one place. Whether you&#39;re tracking performance, optimizing workflows, or making real-time decisions, a well-designed UNS makes it all possible. For more details, check out our article: &lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Introduction to the Unified Namespace&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;core-components-of-uns-and-how-flowfuse-fits-in&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#core-components-of-uns-and-how-flowfuse-fits-in&quot;&gt;&lt;strong&gt;Core Components of UNS and How FlowFuse Fits In&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To truly understand why FlowFuse is the ultimate toolkit for building and managing UNS, we need to explore its core components and see how FlowFuse enhances each one to help create a successful Unified Namespace in industrial IoT environments.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Core Components of UNS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/components-of-uns.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Core Components of UNS: Key Elements to Consider When Building Your UNS&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;1.-connectivity-layer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#1.-connectivity-layer&quot;&gt;&lt;strong&gt;1. Connectivity Layer&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The Connectivity Layer is the foundation of your UNS ecosystem. It’s what collects data from all your devices and systems—whether that’s sensors on the factory floor, PLCs, or IoT devices—and sends it to your UNS. Without a strong connectivity layer, your UNS won’t have the data it needs to create a complete view of your operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How FlowFuse Helps:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is where FlowFuse comes in. Built on the powerful Node-RED platform, FlowFuse takes the complexity out of connecting devices. Whether you&#39;re dealing with legacy systems (think Modbus or OPC-UA) or the latest IoT devices (like MQTT or HTTP), FlowFuse ensures that everything can speak the same language. It connects your old and new technologies, effortlessly streaming data into your UNS.&lt;/p&gt;
&lt;p&gt;With more than 5,000 available community contributed nodes, FlowFuse helps bridge the gap between old and new technologies. For example, if you have machines that use Modbus and new sensors using MQTT, FlowFuse can help them all send data into your UNS without any issues.&lt;/p&gt;
&lt;h4 id=&quot;2.-data-transformation-layer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#2.-data-transformation-layer&quot;&gt;&lt;strong&gt;2. Data Transformation Layer&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Once you’ve connected your devices and started collecting data, it’s time to send that data to your UNS. However, before that happens, there&#39;s an important step: data transformation. The data you collect often comes in different formats, units, or structures, which can create confusion and inefficiency when trying to use it across your system.&lt;/p&gt;
&lt;p&gt;This is where the Data Transformation Layer plays a key role. It’s responsible for standardizing and enriching the data, ensuring it’s consistent, accurate, and ready to be used by your entire IIoT system. Without this layer, your data would remain fragmented and inconsistent—making integration difficult and analysis unreliable. Without proper transformation, your UNS wouldn’t be a true UNS; it would just be an data repository or dump.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How FlowFuse Fits In:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse simplifies data transformation with its intuitive Node-RED interface. This allows engineers to set up complex data processing workflows with minimal effort. Whether you need to convert units of measurement, clean raw data, or reformat it, FlowFuse offers a low-code environment where you can drag and drop nodes to handle these tasks without needing to write custom code.&lt;/p&gt;
&lt;p&gt;Beyond transforming data formats, FlowFuse also enables data contextualization. As raw data flows in, it can be enriched with important metadata—such as timestamps, equipment IDs, or sensor locations—that add context and make the data more meaningful. This is vital for accurate analysis and informed decision-making.&lt;/p&gt;
&lt;p&gt;For instance, imagine temperature readings coming from multiple devices, with some sensors reporting in Celsius, others in Fahrenheit, and others in Kelvin. FlowFuse can automatically standardize all these readings to a single unit (like Celsius) and add contextual information, such as which machine the data came from and its current operating status. This makes the data easy to understand and act upon in your UNS.&lt;/p&gt;
&lt;h4 id=&quot;3.-message-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#3.-message-broker&quot;&gt;&lt;strong&gt;3. Message Broker&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In UNS), the Message Broker is the central hub where your data resides until it’s accessed or consumed by other systems. It ensures that data flows smoothly between devices and applications, using a publish-subscribe (pub-sub) model. Systems &amp;quot;subscribe&amp;quot; to topics and receive automatic updates whenever new data is published, keeping everything in sync and up to date.&lt;/p&gt;
&lt;p&gt;The Message Broker must support the pub-sub model, which is a core requirement for the UNS. For more information on why this model is essential, please read our article on why UNS needs pub-sub. The pub-sub model decouples producers (publishers) from consumers (subscribers), meaning they don’t need to be directly connected or even aware of each other. This decoupling enhances flexibility and scalability. Additionally, it makes the UNS event-driven, eliminating the need for constant polling. Systems only receive data when it’s relevant, boosting efficiency and responsiveness.&lt;/p&gt;
&lt;p&gt;MQTT is the ideal broker that supports the pub-sub model and popular choice for uns. It’s lightweight, efficient, and works well in environments with limited resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How FlowFuse Fits In:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With FlowFuse, you get a built-in MQTT Broker, which means there&#39;s no need to configure and maintain a separate system. This simplifies the connection of all your devices and systems, ensuring smooth data exchange within your UNS.
FlowFuse makes it easy to manage connections, organize topics, and configure security features such as TLS encryption and username/password authentication—all within a single platform. This keeps your setup streamlined and secure.&lt;/p&gt;
&lt;p&gt;The MQTT Broker supports hierarchical topic structuring, allowing you to efficiently organize and manage your data flows. In FlowFuse, you have an interface to monitor all your UNS topics in a tree view, as well as a secure interface to manage your MQTT clients.&lt;/p&gt;
&lt;p&gt;Node-RED in FlowFuse comes with standard MQTT nodes, making it easy to set up secure connections to your broker. You can quickly configure security features like TLS encryption and username/password authentication or dynamically subscribe to topics&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 3px solid rgba(173, 192, 252, 0.55); opacity: 0.3; margin-bottom: 20px;&quot; /&gt;
&lt;p&gt;FlowFuse makes building and managing a Unified Namespace (UNS) easy. It connects devices, transforms data into a usable format, and ensures smooth communication using an MQTT broker. Powered by Node-RED, it works with old and new systems, helping you scale and adapt quickly.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-flowfuse-stand-out-in-industrial-iot%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#what-makes-flowfuse-stand-out-in-industrial-iot%3F&quot;&gt;&lt;strong&gt;What Makes FlowFuse Stand Out in Industrial IoT?&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse isn’t just another tool—it&#39;s a complete solution for building and managing a &lt;strong&gt;Unified Namespace (UNS)&lt;/strong&gt;. While other platforms may specialize in certain areas, FlowFuse brings everything together: connectivity, data transformation, and message brokering, all in one platform.&lt;/p&gt;
&lt;p&gt;Many tools excel in one area but fall short in others. Some may connect devices well but struggle with legacy systems or data transformation. FlowFuse solves these challenges by offering an all-in-one solution that works seamlessly with both modern and legacy systems.&lt;/p&gt;
&lt;p&gt;As an open-source platform, FlowFuse removes the worry of vendor lock-in. You have the flexibility to transition to other services if your needs evolve, without worrying about compatibility issues.&lt;/p&gt;
&lt;p&gt;FlowFuse also includes powerful features tailored for industrial environments. One standout is &lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/&quot;&gt;real-time collaboration&lt;/a&gt;, which allows multiple engineers to work on &lt;strong&gt;Node-RED flows&lt;/strong&gt; simultaneously—speeding up development and deployment. Additionally, you can &lt;a href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/&quot;&gt;remotely manage edge devices&lt;/a&gt;, reducing the need for costly on-site visits for troubleshooting or updates.&lt;/p&gt;
&lt;p&gt;When it comes to scaling, FlowFuse is built to grow with you. It supports horizontal scaling to balance workloads across multiple instances and vertical scaling to add more resources as your needs increase. Whether you’re scaling up or dealing with high workloads, FlowFuse ensures your infrastructure remains stable and efficient.&lt;/p&gt;
&lt;p&gt;Security is a major priority with FlowFuse. It includes features like &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;role-based access control&lt;/a&gt;, encryption, multi-factory authentication, and detailed &lt;a href=&quot;https://flowfuse.com/docs/user/logs/#audit-log&quot;&gt;audit logs&lt;/a&gt; to keep your data secure and meet industry standards.&lt;/p&gt;
&lt;p&gt;On top of that, FlowFuse provides features like &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;DevOps pipeline management&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/&quot;&gt;snapshots for disaster recovery&lt;/a&gt;, and much more, ensuring your systems are always running smoothly and reliably.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/why-flowfuse-is-complete-toolkit-for-uns/#summary&quot;&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is a complete platform for building and managing a Unified Namespace. It combines everything you need—connectivity, data transformation, and message brokering—into one easy-to-use solution. Open-source flexibility makes it simple to connect devices, scale your system, and keep data secure.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/</id>
        <title>Getting Started: Integrating Siemens S7 PLCs with Node-RED</title>
        <summary>A Step-by-Step Beginner&#39;s Guide to Connect, Control, and Monitor Siemens S7 PLCs Using Node-RED</summary>
        <updated>2025-01-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Siemens S7 PLCs are typically programmed using TIA Portal, Siemens&#39; integrated development environment, and communication with external systems usually relies on the S7 protocol (ISO over TCP/IP). 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.&lt;/p&gt;
&lt;h2 id=&quot;prerequisite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#prerequisite&quot;&gt;Prerequisite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before integrating your Siemens S7 PLC with Node-RED, make sure you have the following :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Before downloading the ladder program and all configurations and settings to your PLC, make sure you have the following settings:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Allow PUT/GET Communication from remote partners.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;PUT/GET Communication from remote partners is Allowed&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/allow-put-get-communication.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;PUT/GET Communication from remote partners is Allowed&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provide full access to the PLC (no protection), allowing unrestricted access to data exchange.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Providing complete access to the PLC&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/providing-full-access-to-plc.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Providing complete access to the PLC&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;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 &#39;Optimized Block Access&#39; option is disabled for the data block that your ladder program using.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Untick &#39;Optimized Block Access&#39;.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/optimized-block-access.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Untick &#39;Optimized Block Access.&#39;&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;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 &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt; to install Node-RED on your device.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;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. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up for free&lt;/a&gt; to get started.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;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).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;integrating-siemens-s7-plcs-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#integrating-siemens-s7-plcs-with-node-red&quot;&gt;Integrating Siemens S7 PLCs with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that everything is set up, let&#39;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/tower 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Ladder Logic to Control Outputs for Managing Lights&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ladder-to-control-lights.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;em&gt;Ladder Logic to Control Outputs for Managing Lights&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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 &amp;quot;true,&amp;quot; it activates the corresponding light by altering the state of the Q output, which reflects the change in the physical output.&lt;/p&gt;
&lt;h3 id=&quot;installing-the-s7-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#installing-the-s7-node&quot;&gt;Installing the S7 Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;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 &lt;code&gt;node-red-contrib-s7&lt;/code&gt;, which is quite popular. If this particular node is not suitable for your workflow you can find alternatives in the &lt;a href=&quot;https://flows.nodered.org/search?term=siemens&amp;amp;type=node&quot;&gt;Node-RED catalog&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;steps-to-install-the-s7-node%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#steps-to-install-the-s7-node%3A&quot;&gt;Steps to Install the S7 Node:&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open your Node-RED editor in a web browser.&lt;/li&gt;
&lt;li&gt;Open the main menu by clicking the three horizontal lines in the top-right corner.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Manage Palette&amp;quot; from the menu.&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Install&amp;quot; tab and type &lt;code&gt;node-red-contrib-s7&lt;/code&gt; in the search field.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot; next to the node name.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&quot;addressing-scheme-for-variables-in-node-red-with-the-s7-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#addressing-scheme-for-variables-in-node-red-with-the-s7-node&quot;&gt;Addressing Scheme for Variables in Node-RED with the S7 Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we start, it&#39;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.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Node-RED Address&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Step7 Equivalent&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Data Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB5,X0.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB5.DBX0.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Bit 1 of byte 0 in DB5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB23,BYTE1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB23.DBB1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (Byte)&lt;/td&gt;
&lt;td&gt;Byte 1 (0-255) of DB23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB100,CHAR2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB100.DBB2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Byte 2 of DB100 as Char&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB42,INT3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB42.DBW3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Signed 16-bit number at byte 3 in DB42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB57,WORD4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB57.DBW4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number at byte 4 in DB57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB13,DINT5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB13.DBD5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Signed 32-bit number at byte 5 in DB13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB19,DWORD6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB19.DBD6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 32-bit number at byte 6 in DB19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB21,REAL7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB21.DBD7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point (32)&lt;/td&gt;
&lt;td&gt;Floating point number at byte 7 in DB21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB2,S7.10*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;String (length 10) starting at byte 7 in DB2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;I1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;I1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Bit 0 of byte 1 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Q2.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Q2.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Bit 1 of byte 2 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;M3.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;M3.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Bit 2 of byte 3 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IB4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IB4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (Byte)&lt;/td&gt;
&lt;td&gt;Byte 4 (0-255) in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QB5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QB5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (Byte)&lt;/td&gt;
&lt;td&gt;Byte 5 (0-255) in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MB6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MB6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (Byte)&lt;/td&gt;
&lt;td&gt;Byte 6 (0-255) in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IC7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IB7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Byte 7 of input area as Char&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QC8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QB8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Byte 8 of output area as Char&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MC9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MB9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Byte 9 of memory area as Char&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;II10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IW10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Signed 16-bit number at byte 10 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QI12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QW12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Signed 16-bit number at byte 12 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MI14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MW14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Signed 16-bit number at byte 14 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IW16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IW16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number at byte 16 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QW18&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QW18&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number at byte 18 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MW20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MW20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number at byte 20 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IDI22&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ID22&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Signed 32-bit number at byte 22 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QDI24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QD24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Signed 32-bit number at byte 24 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MDI26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MD26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Signed 32-bit number at byte 26 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ID28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ID28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 32-bit number at byte 28 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QD30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QD30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 32-bit number at byte 30 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MD32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MD32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 32-bit number at byte 32 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IR34&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IR34&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point&lt;/td&gt;
&lt;td&gt;Floating point number at byte 34 in input area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QR36&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QR36&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point&lt;/td&gt;
&lt;td&gt;Floating point number at byte 36 in output area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MR38&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MR38&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point&lt;/td&gt;
&lt;td&gt;Floating point number at byte 38 in memory area&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB1,DT0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;Timestamp in DATE_AND_TIME format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB1,DTZ10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;Timestamp in DATE_AND_TIME format (UTC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB2,DTL2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;Timestamp in DTL format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB2,DTLZ12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;Timestamp in DTL format (UTC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB57,RWORD4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB57.DBW4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number, Little-Endian at byte 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB13,RDI5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DB13.DBD5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (32-bit)&lt;/td&gt;
&lt;td&gt;Signed 32-bit number, Little-Endian at byte 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MRW20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MW20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number (16-bit)&lt;/td&gt;
&lt;td&gt;Unsigned 16-bit number, Little-Endian at byte 20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;If you wanted integrate Siemens LOGO, please refer to the node&#39;s &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-s7&quot;&gt;README&lt;/a&gt;, as the addressing differs.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-s7-node-to-connect-to-the-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#configuring-the-s7-node-to-connect-to-the-plc&quot;&gt;Configuring the S7 Node to Connect to the PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you have all the necessary knowledge and setup, let&#39;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&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the S7 node onto the Node-RED canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the S7 node and click on the &amp;quot;+&amp;quot; icon to add a PLC configuration.&lt;/li&gt;
&lt;li&gt;Select &amp;quot;Ethernet (ISO on TCP)&amp;quot; as the transport protocol, then enter your PLC&#39;s IP address. The default port (102) is used for S7 communication, so leave it unchanged.&lt;/li&gt;
&lt;li&gt;Set the Mode to &amp;quot;Rack,&amp;quot; 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing window from where you will get the Rack No and Slot No&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/showing-rack-and-slot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing window from where you will get the Rack No and Slot No&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Enter the Cycle Time (interval for communication with the PLC) and Timeout Duration (maximum time to wait for a response).&lt;/li&gt;
&lt;li&gt;Once done, switch to the Variables tab and add all the variables with the correct address and name you want to read or write.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Adding Variables into s7 node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/s7-config-variables.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Adding Variables into s7 node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;After adding the variables, click Add and then Done.&lt;/li&gt;
&lt;li&gt;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 &amp;quot;online&amp;quot; status.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring S7 node for connection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/s7-connection-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring S7 node for connection&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;writing-data-to-the-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#writing-data-to-the-plc&quot;&gt;Writing Data to the PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you’ve configured the connection, it’s time to use Node-RED to write data to the PLC to control light.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the s7-out node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node and select the variable to which you want to update or write a value.&lt;/li&gt;
&lt;li&gt;Select the PLC configuration that we have added.&lt;/li&gt;
&lt;li&gt;Click Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring S7-out Node to write data to plc&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/configuring-s7-out-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring S7-out Node to write data to plc&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;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 &lt;a href=&quot;https://flowfuse.com/platform/dashboard/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; for easier interaction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;AilWMNPzP1Q&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;If you&#39;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: &lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/&quot;&gt;Exploring FlowFuse Project Nodes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;reading-data-from-the-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#reading-data-from-the-plc&quot;&gt;Reading Data from the PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we’ve covered how to write data to your Siemens S7 PLC, let&#39;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.&lt;/p&gt;
&lt;p&gt;However, before we dive in, it&#39;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: &lt;a href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/&quot;&gt;Modernize Your Legacy Industrial Data - Part 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Ladder diagram showing a custom function that stores the status of outputs in a single word within the PLC.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/custom-function-storing-bits-in-word.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Custom ladder diagram function storing output statuses in a single word for optimized data retrieval.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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&#39;s simply one approach that works for this particular scenario. Feel free to adapt or explore other methods that might better suit your setup.&lt;/p&gt;
&lt;p&gt;Additionally, if the data you’re reading is mission-critical and you can&#39;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.&lt;/p&gt;
&lt;p&gt;Now, let’s begin reading the data from the PLC.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;code&gt;s7-in&lt;/code&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node to open the configuration and select the appropriate PLC configuration from the list of available connections.&lt;/li&gt;
&lt;li&gt;Choose the appropriate mode based on your requirements. If you want to read only one variable, select &amp;quot;Single Variable Mode&amp;quot;. In this mode, the &amp;quot;Variable&amp;quot; dropdown will allow you to select only a single variable at a time. If you need to read multiple variables, you can select &amp;quot;All Variables&amp;quot; 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.&lt;/li&gt;
&lt;li&gt;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 &lt;code&gt;DB.DBW2&lt;/code&gt;, the format in the s7-in node will be &lt;code&gt;DB,WORD2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enable the &amp;quot;Emit only when value changes (diff)&amp;quot; option to ensure that the node only triggers when the value of the variable changes, reducing unnecessary reads and improving efficiency.&lt;/li&gt;
&lt;li&gt;Once your configuration is set, click &amp;quot;Done&amp;quot; and then deploy the flow to start reading data from the PLC.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring S7-in Node to Read data from plc&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/configuring-s7-in-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring S7-in Node to Read data from plc&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can add a &amp;quot;Debug&amp;quot; node to the &lt;code&gt;s7-in&lt;/code&gt; node&#39;s output to verify that the data is being read correctly.&lt;/p&gt;
&lt;p&gt;Once you see the printed data, you might be surprised, or perhaps you already expected this: since the word data type we&#39;re reading is not directly available in Node.js or Node-RED, we&#39;ll receive it as an integer. But don&#39;t worry—you can convert it into the format that suits your needs using node-red-contrib-buffer-parser. In this integer scenario, you&#39;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.&lt;/p&gt;
&lt;p&gt;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&#39;ve retrieved. You can use the FlowFuse Dashboard, as suggested earlier.&lt;/p&gt;
&lt;p&gt;The video below shows the updated dashboard interface used to monitor the stack light LED status:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;Nlyk_BATKGE&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;p&gt;Here is the flow you can import into your FlowFuse remote instance and deploy. Ensure that you have installed &lt;code&gt;node-red-contrib-s7&lt;/code&gt; and &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt;. 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.&lt;/p&gt;
&lt;div id=&quot;nr-flow-202&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow202 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;061313277591a004&#92;&quot;,&#92;&quot;a8499bc2443f0bd9&#92;&quot;,&#92;&quot;2974dd47fda54b9c&#92;&quot;,&#92;&quot;4c009f6076f47eb6&#92;&quot;,&#92;&quot;f4378d1e7c268e1e&#92;&quot;,&#92;&quot;63abd67743263739&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:99,&#92;&quot;w&#92;&quot;:732,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;061313277591a004&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;f2f06ce027c97e4d&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Button_1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button to Turn the RED Light ON&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a8499bc2443f0bd9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;f2f06ce027c97e4d&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Button_2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button to turn the Yellow light ON&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2974dd47fda54b9c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;f2f06ce027c97e4d&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Button_3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button to turn Green light  ON&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4c009f6076f47eb6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project in node to control the red light&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_red&#92;&quot;,&#92;&quot;x&#92;&quot;:230,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;061313277591a004&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f4378d1e7c268e1e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project in node to control the yellow light&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_yellow&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a8499bc2443f0bd9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;63abd67743263739&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;0ffc8c2703b5e059&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project in node to control the green light&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_green&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2974dd47fda54b9c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f2f06ce027c97e4d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 endpoint&#92;&quot;,&#92;&quot;transport&#92;&quot;:&#92;&quot;iso-on-tcp&#92;&quot;,&#92;&quot;address&#92;&quot;:&#92;&quot;192.168.1.6&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;102&#92;&quot;,&#92;&quot;rack&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;slot&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;localtsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;localtsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;remotetsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;remotetsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;connmode&#92;&quot;:&#92;&quot;rack-slot&#92;&quot;,&#92;&quot;adapter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;busaddr&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;cycletime&#92;&quot;:&#92;&quot;1000&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;2000&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;S7 Connection Configuration&#92;&quot;,&#92;&quot;vartable&#92;&quot;:[{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X0.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button_1&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X0.1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button_2&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X0.2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Button_3&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,WORD2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;LightStatus&#92;&quot;}]},{&#92;&quot;id&#92;&quot;:&#92;&quot;23fd40630dbef712&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;a45637418005d0e5&#92;&quot;,&#92;&quot;a8ea1622d1fad4ba&#92;&quot;,&#92;&quot;8d9a9dc4183a778e&#92;&quot;,&#92;&quot;d60a74a5430df7ae&#92;&quot;],&#92;&quot;x&#92;&quot;:54,&#92;&quot;y&#92;&quot;:339,&#92;&quot;w&#92;&quot;:972,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;a45637418005d0e5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;23fd40630dbef712&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;f2f06ce027c97e4d&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;LightStatus&#92;&quot;,&#92;&quot;diff&#92;&quot;:true,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d60a74a5430df7ae&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a8ea1622d1fad4ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;23fd40630dbef712&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project out node to send the light status&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;project&#92;&quot;:&#92;&quot;c51f38c2-6c80-442a-a9e2-10ddd68fb606&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_status&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8d9a9dc4183a778e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;buffer-parser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;23fd40630dbef712&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;data&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;dataType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;specification&#92;&quot;:&#92;&quot;spec&#92;&quot;,&#92;&quot;specificationType&#92;&quot;:&#92;&quot;ui&#92;&quot;,&#92;&quot;items&#92;&quot;:[{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;red&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:0,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;yellow&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:1,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;green&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;length&#92;&quot;:1,&#92;&quot;offsetbit&#92;&quot;:2,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;type&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;offset&#92;&quot;:0,&#92;&quot;length&#92;&quot;:16,&#92;&quot;offsetbit&#92;&quot;:0,&#92;&quot;scale&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;mask&#92;&quot;:&#92;&quot;&#92;&quot;}],&#92;&quot;swap1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap3&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap1Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap2Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap3Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;msgProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;msgPropertyType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;resultType&#92;&quot;:&#92;&quot;keyvalue&#92;&quot;,&#92;&quot;resultTypeType&#92;&quot;:&#92;&quot;return&#92;&quot;,&#92;&quot;multipleResult&#92;&quot;:false,&#92;&quot;fanOutMultipleResult&#92;&quot;:false,&#92;&quot;setTopic&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a8ea1622d1fad4ba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d60a74a5430df7ae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;buffer-maker&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;23fd40630dbef712&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;specification&#92;&quot;:&#92;&quot;spec&#92;&quot;,&#92;&quot;specificationType&#92;&quot;:&#92;&quot;ui&#92;&quot;,&#92;&quot;items&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;1stword&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;uint16le&#92;&quot;,&#92;&quot;length&#92;&quot;:1,&#92;&quot;dataType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;data&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;swap1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap3&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;swap1Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap2Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;swap3Type&#92;&quot;:&#92;&quot;swap&#92;&quot;,&#92;&quot;msgProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;msgPropertyType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8d9a9dc4183a778e&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow202.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-202&#39;) })&lt;/script&gt;
&lt;p&gt;Below is the flow that you can import and deploy into the hosted instance created on FlowFuse. With this flow, you&#39;ll have a dashboard to control and monitor the tower lights. Just make sure you have installed &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; and &lt;code&gt;@flowfuse/node-red-dashboard-2-ui-led&lt;/code&gt;, and ensure the hosted instance is in the same FlowFuse team as your remote instance.&lt;/p&gt;
&lt;div id=&quot;nr-flow-203&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow203 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;1e6a379c83bac6b4&#92;&quot;,&#92;&quot;f015125886fec5a6&#92;&quot;,&#92;&quot;76c696f160db3ca2&#92;&quot;,&#92;&quot;1974cfc417898151&#92;&quot;,&#92;&quot;9c503fe31081dc2f&#92;&quot;,&#92;&quot;9501e2eb7690a0b5&#92;&quot;],&#92;&quot;x&#92;&quot;:74,&#92;&quot;y&#92;&quot;:79,&#92;&quot;w&#92;&quot;:652,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e6a379c83bac6b4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;YELLOW&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;yellow&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:false,&#92;&quot;enablePointerdown&#92;&quot;:true,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:true,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1974cfc417898151&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f015125886fec5a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;RED&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;red&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:false,&#92;&quot;enablePointerdown&#92;&quot;:true,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:true,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9501e2eb7690a0b5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;76c696f160db3ca2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;GREEN&#92;&quot;,&#92;&quot;order&#92;&quot;:6,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;green&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:false,&#92;&quot;enablePointerdown&#92;&quot;:true,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:true,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9c503fe31081dc2f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1974cfc417898151&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project out node to control the yellow light&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;project&#92;&quot;:&#92;&quot;c51f38c2-6c80-442a-a9e2-10ddd68fb606&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_yellow&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9c503fe31081dc2f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project out node to control the green light&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;project&#92;&quot;:&#92;&quot;c51f38c2-6c80-442a-a9e2-10ddd68fb606&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_green&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9501e2eb7690a0b5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1f56099d53798b99&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Project out node to control the red light&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;project&#92;&quot;:&#92;&quot;c51f38c2-6c80-442a-a9e2-10ddd68fb606&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_control_red&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Group 1&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;62085b96f178f643&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:1,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;62085b96f178f643&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Page 1&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;02c25e8a30f9379d&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;f6f5e7ae33bf6878&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;02c25e8a30f9379d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:true,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;hidden&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;f6f5e7ae33bf6878&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#1a1a1a&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;d163a7ab23f7458f&#92;&quot;,&#92;&quot;20d211683534362b&#92;&quot;,&#92;&quot;b1477193956e591b&#92;&quot;,&#92;&quot;fb8801a4accc3c15&#92;&quot;,&#92;&quot;2f62948afcfde259&#92;&quot;,&#92;&quot;6966f129e718d20a&#92;&quot;,&#92;&quot;a5cecf8e8adf6eef&#92;&quot;],&#92;&quot;x&#92;&quot;:74,&#92;&quot;y&#92;&quot;:299,&#92;&quot;w&#92;&quot;:872,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;d163a7ab23f7458f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-led&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Status of RED light&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;labelPlacement&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;labelAlignment&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;states&#92;&quot;:[{&#92;&quot;value&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ff0000&#92;&quot;},{&#92;&quot;value&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#787878&#92;&quot;}],&#92;&quot;allowColorForValueInMessage&#92;&quot;:false,&#92;&quot;shape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;showBorder&#92;&quot;:true,&#92;&quot;showGlow&#92;&quot;:true,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;20d211683534362b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-led&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Status of Yellow light&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;labelPlacement&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;labelAlignment&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;states&#92;&quot;:[{&#92;&quot;value&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#c8ff00&#92;&quot;},{&#92;&quot;value&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#787878&#92;&quot;}],&#92;&quot;allowColorForValueInMessage&#92;&quot;:false,&#92;&quot;shape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;showBorder&#92;&quot;:true,&#92;&quot;showGlow&#92;&quot;:true,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b1477193956e591b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-led&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Status of Green light&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d4102809d229cb95&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;labelPlacement&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;labelAlignment&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;states&#92;&quot;:[{&#92;&quot;value&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#41891a&#92;&quot;},{&#92;&quot;value&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#787878&#92;&quot;}],&#92;&quot;allowColorForValueInMessage&#92;&quot;:false,&#92;&quot;shape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;showBorder&#92;&quot;:true,&#92;&quot;showGlow&#92;&quot;:true,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb8801a4accc3c15&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.red&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d163a7ab23f7458f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2f62948afcfde259&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.yellow&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;20d211683534362b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6966f129e718d20a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.green&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b1477193956e591b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5cecf8e8adf6eef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eb351e503901d04f&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;82cc6997fddd0b4b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in node to receive the light status&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;light_status&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fb8801a4accc3c15&#92;&quot;,&#92;&quot;2f62948afcfde259&#92;&quot;,&#92;&quot;6966f129e718d20a&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow203.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-203&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;troubleshooting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;&amp;quot;Error: This service is not implemented on the modeul or frame error was reported&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/error.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;&amp;quot;Error: This service is not implemented on the modeul or frame error was reported&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/integrating-siemens-s7-plcs-with-node-red-guide/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;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&#39;re writing data to control outputs or reading sensor values, Node-RED offers a flexible, user-friendly platform for industrial automation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/</id>
        <title>FlowFuse 2.13: Remote Instances, UNS Schemas &amp; Improved Management at Scale</title>
        <summary>FlowFuse 2.13 brings clarity to &quot;Instances&quot; in FlowFuse, automated documentation for your MQTT Broker, better management and deployment to multiple Remote Instances, and more.</summary>
        <updated>2025-01-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Happy New Year everyone! We&#39;re back with another release of FlowFuse, and whilst it&#39;s been a shorter sprint for us this time round, with most of the team out for a well-earned break over Christmas and New Year, that hasn&#39;t stopped us packing in lot of great new value into FlowFuse nonetheless.&lt;/p&gt;
&lt;h2 id=&quot;hosted-%26-remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#hosted-%26-remote-instances&quot;&gt;Hosted &amp;amp; Remote Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This release you&#39;ll notice that we&#39;ve changed the terminology of two of our key concepts in FlowFuse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instances&lt;/strong&gt; are now referred to as &lt;strong&gt;Hosted Instances&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Devices&lt;/strong&gt; are now referred to &lt;strong&gt;Remote Instances&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We were finding that customers and prospects were getting confused over the term &amp;quot;Device&amp;quot;, when in fact, it is a running &lt;em&gt;Instance&lt;/em&gt; of Node-RED. You can have many Remote Instances running on the same piece of hardware, all using the FlowFuse Device Agent, and the term, &amp;quot;Device&amp;quot; made that misleading.&lt;/p&gt;
&lt;p&gt;Remote Instances are just instances of Node-RED, deployed onto your own hardware and managed via FlowFuse and the FlowFuse Device Agent. We hope this change will make it clearer for everyone, and wanted to include this graphic which shows the updated terminology in the hierarchy of FlowFuse:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Hierarchy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-hierarchy.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Diagram to show the hierarchy of different concepts in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;documenting-your-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#documenting-your-uns&quot;&gt;Documenting Your UNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just under three months ago, we &lt;a href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/&quot;&gt;released our own MQTT Service&lt;/a&gt;, making it easy for your to configure MQTT clients through FlowFuse, and connect your hardware and applications. With the Unified Namespace (UNS) growing in popularity in Industry, we wanted to make sure that if you&#39;re using MQTT to run your UNS, then FlowFuse offers the best experience for managing it.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Topic Hierarchy Schema&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-topic-schema.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With this in mind, we&#39;re now generating a formal schema for your MQTT Broker&#39;s topic hierarchy automatically, and we&#39;ve made it possible to access the underlying schema through the FlowFuse interface. The schema we generate is using the industry-standard, open-sourced, &lt;a href=&quot;https://www.asyncapi.com/&quot;&gt;AsyncAPI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in learning more about UNS, then we recommend taking a look at some of the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Introduction to the Unified Namespace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/&quot;&gt;Why you need a Unified Namespace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Building a Unified Namespace (UNS) with FlowFuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/whitepaper/uns-decoupling-data-producers-and-consumers/&quot;&gt;&lt;strong&gt;Free whitepaper:&lt;/strong&gt; UNS - Decoupling data producers and consumers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;future-plans&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#future-plans&quot;&gt;Future Plans&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is very much a first iteration and we have work underway to improve it. Right now, the generated spec is pretty minimal - there is lots of scope to add more information and present it in a clearer and more interactive format. This will make it easy for your whole development team, and anyone else that needs to know, to get a clear picture of the topics and payloads that are being used in your MQTT Broker.&lt;/p&gt;
&lt;p&gt;We&#39;re also looking at how this information can enhance the development experience within Node-RED itself.&lt;/p&gt;
&lt;h2 id=&quot;managing-groups-of-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#managing-groups-of-instances&quot;&gt;Managing Groups of Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve introduced a new view in FlowFuse which you can find in the &amp;quot;Operations&amp;quot; section of the side navigation. This new view is called &amp;quot;Groups&amp;quot; and it allows you to group your Remote Instances together, making it easier to manage and deploy to multiple instances at once.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Groups view&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-team-groups.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This functionality has been in FlowFuse for a little while, but was buried down in the &amp;quot;Applications&amp;quot; view, and found users were missing it. We&#39;ve now brought it to the forefront, and made it easier to use, and help you deploy out to thousands of Remote Instances with the single click of a button.&lt;/p&gt;
&lt;h2 id=&quot;new-onboarding-tour&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#new-onboarding-tour&quot;&gt;New Onboarding Tour&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot from the new Free Tier onboarding tour&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/free-tier-tour.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We have a new onboarding tour that will be shown to those users signing up to our &lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/&quot;&gt;new Free Tier on FlowFuse Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This tour is purpose built to help you get up and running with your first Remote Instance in FlowFuse, setting up the Device Agent on your own hardware, and accessing your Remote Instance via FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;in-case-you-missed-it...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#in-case-you-missed-it...&quot;&gt;In Case You Missed It...&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last month we &lt;a href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/&quot;&gt;released a new Free Tier on FlowFuse Cloud&lt;/a&gt;, but announced it in the same article as our latest release and so a lot of the other new features we&#39;d added to FlowFuse were lost in the weeds a little. We had a few self-hosted customers mention that they missed the updates for 2.12, so we also wanted to re-highlight some new features from that release too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pipelines&lt;/strong&gt; - New view at the team-level to manage your DevOps Pipelines, making it easier to deploy between development, test and production environments. Pipelines can also be used to push updates out to thousands of Remote Instances at once using the new &amp;quot;Groups&amp;quot; feature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bill of Materials&lt;/strong&gt; - New view at the team-level to get a clear picture of all dependencies that your Instances are using. Makes it easier to manage out-of-date packages, and help with auditing and compliance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device Agent Performance Improvements&lt;/strong&gt; - For those running Node-RED 4.0.x and higher, the Device Agent has had some significant updates to performance, making the experience of remote editing much faster and smoother, especially when the device is on a slow network link.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboards in iFrames&lt;/strong&gt; - FlowFuse-hosted Dashboards can now be configured to run inside iFrames. You can find this option under the &amp;quot;Settings&amp;quot; of the Instance in question.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#what-else-is-new%3F&quot;&gt;What Else Is New?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.13 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.13.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/flowfuse-release-2-13/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/</id>
        <title>MQTT: The Frontrunner for Your UNS Broker - Part 2</title>
        <summary>Why MQTT is the Best Choice for Your UNS Broker</summary>
        <updated>2025-01-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/&quot;&gt;Part 1&lt;/a&gt;, we discussed the  reasons behind MQTT&#39;s popularity as a choice for Unified Namespace (UNS) implementations; focusing on its lightweight design, low latency, and reliable message delivery. In this second part, we’ll explore additional factors that further establish MQTT as the leading protocol for UNS brokers, diving into its connectivity, scalability, structured topic management.&lt;/p&gt;
&lt;h2 id=&quot;wide-connectivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/#wide-connectivity&quot;&gt;Wide Connectivity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For your UNS to be truly effective, it must be able to connect seamlessly with every part of your IIoT environment—whether it’s a device or the cloud. MQTT is an excellent protocol for this because it’s widely adopted in both cloud-based systems and industrial environments.&lt;/p&gt;
&lt;p&gt;In a typical industrial data architecture, you typically have a mix of physical devices (like sensors and machines) and cloud systems. To make real-time decisions, data needs to flow seamlessly from the shop floor to the cloud. MQTT excels at connecting modern devices with the cloud. However, one challenge is that it doesn’t natively support older systems that typically use protocols like OPC UA or MODBUS.&lt;/p&gt;
&lt;p&gt;This isn’t a major issue, though. You can bridge the gap using tools like FlowFuse and Node-RED, which allow MQTT to communicate with older systems.&lt;/p&gt;
&lt;p&gt;Overall, MQTT has better compatibility than many other protocols. Some other protocols may offer better compatibility, but they can hardly surpass MQTT in meeting the core requirements of a UNS.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img width=&quot;550px&quot; data-zoomable=&quot;&quot; alt=&quot;MQTT&#39;s Compatibility&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-compatiblity.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;MQTT&#39;s Compatibility&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;easily-scalable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/#easily-scalable&quot;&gt;Easily Scalable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A UNS broker needs to be able to grow as your factory or system expands. What starts with just a few sensors or devices might quickly scale up to hundreds or thousands over time. Can MQTT handle this growth? Absolutely.&lt;/p&gt;
&lt;p&gt;MQTT&#39;s lightweight architecture, based on a simple publish-subscribe model, makes it easy to scale. Adding new devices doesn’t disrupt existing operations. The system can handle thousands of devices and connections without performance issues. As your network grows, new devices can easily connect to the broker and start exchanging data without major changes to the infrastructure.&lt;/p&gt;
&lt;p&gt;MQTT brokers handle large volumes of data and can distribute messages to many clients at once. This ensures that as more devices are added, the system remains stable. The broker can also scale horizontally, meaning you can add more brokers or resources to handle the increased load, without affecting the performance or reliability of the system.&lt;/p&gt;
&lt;h2 id=&quot;semantic-hierarchy-with-topics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/#semantic-hierarchy-with-topics&quot;&gt;Semantic Hierarchy with Topics&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When setting up a UNS, it’s not just about collecting all your data in one place—it’s about organizing it so that it’s easy to navigate. A semantic hierarchy helps do this by arranging data from broad categories down to more specific details. For example, in a factory, you might have levels like factory, area, line, and machine, with data points like temperature or humidity at the bottom. This is similar to how files are organized in folders, making it simple to find what you need.&lt;/p&gt;
&lt;p&gt;MQTT works well for this kind of organization because its topics are already structured in a hierarchical way. Topics in MQTT are like paths that break down data into different levels, such as &lt;code&gt;factory/area-2/line-1/machine-5/temperature&lt;/code&gt;. You can easily follow these paths to find the exact data you need. Furthermore, MQTT supports wildcard characters, which offer flexibility for subscriptions. The # wildcard matches all levels beneath a given level, so a subscription to &lt;code&gt;factory/#&lt;/code&gt; will match any topic under the &amp;quot;factory&amp;quot; level, regardless of how deep the path goes. Similarly, the &lt;code&gt;+&lt;/code&gt; wildcard matches only a single level, so &lt;code&gt;factory/+/line-1/machine-5/temperature&lt;/code&gt; will match any topic that follows the same structure but with different areas.&lt;/p&gt;
&lt;p&gt;While  AMQP and Kafka also support topics and wildcards, they handle them differently. AMQP uses routing keys for message routing rather than a direct hierarchical topic structure like MQTT. Though AMQP has a topic exchange for routing based on patterns (similar to topics), it doesn’t provide the same natural hierarchical organization. Kafka, on the other hand, uses a flat topic model without a hierarchy, which can make it more difficult to maintain clarity and structure as the system grows in complexity. While both AMQP and Kafka can still be used in a UNS, their lack of a natural topic hierarchy makes them more challenging manage compared to MQTT, which provides a simpler, more intuitive way to organize and access data.&lt;/p&gt;
&lt;p&gt;In conclusion, MQTT is an excellent choice for your UNS broker because it offers simplicity, scalability, and efficient data organization. Its lightweight design ensures smooth performance as your system grows, while the publish-subscribe  model decouples producers and consumers, allowing them to operate independently. This reduces direct dependencies between devices and systems, making the overall architecture more flexible and easier to scale. MQTT’s hierarchical topic structure further simplifies data management and access. Compared to other options like AMQP and Kafka, MQTT provides a more intuitive, reliable, and scalable and most importantly simple solution for building a Unified Namespace that can adapt to future needs.&lt;/p&gt;
&lt;h2 id=&quot;build-your-uns-with-flowfuse-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns-part-2/#build-your-uns-with-flowfuse-now&quot;&gt;Build Your UNS with FlowFuse Now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand why MQTT is the best choice for your UNS, it’s time to build it. FlowFuse is the ideal platform for implementing your UNS with MQTT.&lt;/p&gt;
&lt;p&gt;Please read our article: &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Building Your UNS with FlowFuse&lt;/a&gt; where I show you how to build it quickly—just in 15 minutes!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why choose FlowFuse?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse is an industrial data platform that leverages the power of Node-RED, a popular open-source low-code platform for industrial automation. With over 5000 community-contributed nodes, it simplifies the process of collecting, transforming, and integrating data from a wide variety of industrial hardware and services, supporting nearly all industrial protocols. This means you have nearly everything you need to implement a UNS—all you need is the MQTT broker service.&lt;/p&gt;
&lt;p&gt;Good news! Recently, FlowFuse has added a built-in MQTT broker service within the platform, making it even easier to manage your MQTT connections. This includes an interface for securely managing MQTT clients and, most importantly, a comprehensive topic hierarchy monitoring tool that’s ideal for managing your UNS.&lt;/p&gt;
&lt;p&gt;FlowFuse not only allows you to build and manage your UNS, but also provides a collaborative environment where teams can work in real time. It offers scalability, security, and ease of use, making it simple to grow your system as your needs evolve.&lt;/p&gt;
&lt;p&gt;With FlowFuse, you get everything you need to handle data pipelines, implement a UNS, and scale efficiently—all within a single platform.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/</id>
        <title>MQTT: The Frontrunner for Your UNS Broker - Part 1</title>
        <summary>Why MQTT is the Best Choice for Your UNS Broker</summary>
        <updated>2025-01-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Choosing the right broker for your UNS is crucial. It must support real-time data, scale easily, and integrate seamlessly with devices and services. MQTT often comes out as the best choice for these needs.&lt;/p&gt;
&lt;p&gt;In this first part of our series, we’ll explain why MQTT is the standout choice for UNS implementations. With its focus on lightweight, real-time messaging and robust reliability, MQTT delivers the performance IIoT environments demand, making it the perfect fit for a future-proof, scalable UNS.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt; is a data architecture (not just a tool or new technology) that centralizes and organizes data from various sources into a single, unified structure. It eliminates data silos by providing a standardized way to represent, access, and share information across different devices, systems, and services. For more information on what is UNS, read our article: &lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Introduction to the Unified Namespace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When choosing a broker for your UNS, it&#39;s crucial to consider how well the selected broker fits the specific requirements of your IIoT environment, including the types of devices and systems involved, as well as factors like scalability, reliability, and ease of integration. Several options are available alongside MQTT, including &lt;a href=&quot;https://flowfuse.com/node-red/protocol/amqp/&quot;&gt;AMQP&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka&lt;/a&gt;, and cloud message brokers like AWS Kinesis and GCP Pub/Sub. While these alternatives offer unique features, MQTT stands out, and we’ll explain why later in this article. But If you’re interested in a brief overview of why these alternatives are not the best fit for UNS, check out our article: &lt;a href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/&quot;&gt;Unified Namespace: What Broker to Use?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is also an ongoing debate regarding the use of OPC-UA and other protocols for implementing UNS. While I won’t dive into this in detail here as i havent explored it much yet, I encourage you to start with the approach we call reverse engineering. First, understand why MQTT is the preferred choice for implementing UNS, and then explore how its features align with UNS needs. From there, you can evaluate whether other protocols offer similar capabilities. By following this process, you will find the right answer of your questions.&lt;/p&gt;
&lt;h2 id=&quot;background-of-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/#background-of-mqtt&quot;&gt;Background of MQTT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into its specific advantages for UNS, let’s take a brief look at the history of &lt;strong&gt;MQTT&lt;/strong&gt; and how it became the backbone of modern IoT communication.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/mqtt/&quot;&gt;MQTT&lt;/a&gt; was developed in the late 1990s by Andy Stanford-Clark at IBM and Arlen Nipper at Eurotech to address communication challenges in low-bandwidth, unreliable networks. This early focus on lightweight messaging paved the way for MQTT to become a pioneering solution for the rapidly expanding IoT space.&lt;/p&gt;
&lt;p&gt;Since then, MQTT has evolved significantly. The protocol has gone through several iterations, from MQTT 3.1.1 to the more feature-rich MQTT 5.0, each version enhancing the protocol&#39;s capabilities to meet the demands of an increasingly connected world. Today, more than 25 years later, MQTT remains the &lt;strong&gt;de facto protocol&lt;/strong&gt; for IoT applications, and its simplicity, scalability, and reliability continue to make it an ideal choice for industrial systems.&lt;/p&gt;
&lt;p&gt;But, what exactly makes MQTT the frontrunner for UNS implementations? Let&#39;s take a deeper look at some of its key features?&lt;/p&gt;
&lt;h2 id=&quot;publish-subscribe-model-and-event-driven-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/#publish-subscribe-model-and-event-driven-architecture&quot;&gt;Publish-Subscribe Model and Event-Driven Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the standout features of MQTT is its publish-subscribe (Pub/Sub) model, which is the primary need of an UNS. In this model, data producers (such as sensors or devices) don’t need to know who is receiving the data or how many consumers are out there. Instead, they publish their data to a central broker, and any consumer (like a monitoring system, data warehouse, or analytics engine) that is interested simply subscribes to the relevant data stream.&lt;/p&gt;
&lt;p&gt;This approach decouples producers and consumers, removing the need for direct, point-to-point connections between them. In traditional systems, every device would need to know about every other device it communicates with, leading to a messy, tightly coupled network. As your IIoT ecosystem grows, managing these connections becomes increasingly difficult and prone to error. But with MQTT’s Pub/Sub model, adding new devices or services is seamless and doesn’t disrupt existing data flows.&lt;/p&gt;
&lt;p&gt;Beyond this, MQTT’s event-driven architecture takes the system to a whole new level of efficiency and responsiveness. Imagine a scenario where a machine detects an issue—rather than waiting for a periodic check-in, the event is immediately sent to the right consumer, triggering an alert in real time. This push mechanism is far more efficient than traditional polling, where systems continuously ask, “Is there new data yet?” and waste precious resources in the process.&lt;/p&gt;
&lt;p&gt;With MQTT, data is pushed as soon as it’s available, enabling faster decision-making and real-time responses. This means events like machine faults or environmental changes are addressed immediately, making the Our UNS more agile, responsive, and capable of scaling as needed which is one of priamary need of IIoT environemnt.&lt;/p&gt;
&lt;p&gt;If you’d like to understand the importance of Publish-Subscribe (Pub/Sub) architecture in detail for UNS, I highly recommend reading our article: &lt;a href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/&quot;&gt;Why UNS Needs Pub/Sub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;low-latency-and-lightweight-messaging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/#low-latency-and-lightweight-messaging&quot;&gt;Low Latency and Lightweight Messaging&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Downtime in industrial operations can be very costly—ranging from $15,000 to $20,000 per minute or more. For engineers and operators watching over machines, waiting for data can mean the difference between smooth operations and expensive disruptions,  If you&#39;re interested in learning more about downtime, read this research by Siemens from 2022: &lt;a href=&quot;https://assets.new.siemens.com/siemens/assets/api/uuid:3d606495-dbe0-43e4-80b1-d04e27ada920/dics-b10153-00-7600truecostofdowntime2022-144.pdf&quot;&gt;True Cost of Downtime 2022&lt;/a&gt;. Low-latency messaging is key in these situations, which is why data architectures like UNS are being explored to make sure systems and devices in your IIoT setup communicate without delays. MQTT is the protocol that makes this possible.&lt;/p&gt;
&lt;p&gt;As we explored, MQTT uses a publish-subscribe model, which is built for real-time communication with minimal delay. Unlike traditional request-response systems that can cause delays due to constant querying, MQTT keeps a persistent connection open. Once a device connects, it can immediately send data or receive updates on important topics, cutting out the need for repeated requests and making sure data flows instantly. This helps engineers make decisions and take action faster.&lt;/p&gt;
&lt;p&gt;In addition to being fast, MQTT is very efficient. Its messages are small and use little bandwidth—important when working with low-bandwidth networks or many connected devices. Even with limited resources, MQTT allows devices to send data without overwhelming the system. The result? As soon as a sensor detects a change—like a temperature spike or a production issue—it can send the information right away to the right system, triggering immediate actions to avoid costly downtime.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;MQTT Packet Structer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-packate-size.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;  &lt;em&gt;MQTT Packet Structer&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;reliability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2025/01/mqtt-frontrunner-for-uns/#reliability&quot;&gt;Reliability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to building a UNS, reliability is absolutely crucial. Missing or duplicate data can lead to poor decision-making, system malfunctions, or even costly downtime—things no one wants in their IIoT environment.&lt;/p&gt;
&lt;p&gt;This is where MQTT truly shines. It’s built with a Quality of Service (QoS) mechanism that allows you to control how reliably your messages are delivered. Depending on the level you choose, you can ensure that data is delivered exactly as you need it, without compromising on system performance.&lt;/p&gt;
&lt;p&gt;MQTT offers three levels of QoS to suit different use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QoS 0 - &amp;quot;At most once&amp;quot;: The message is delivered once and isn’t acknowledged. This is fine for non-critical data where the occasional loss of a message is acceptable.&lt;/li&gt;
&lt;li&gt;QoS 1 - &amp;quot;At least once&amp;quot;: The message is delivered at least once, with an acknowledgment to ensure it was received. This is ideal for most IIoT applications, where you need reliable delivery, but duplicate messages are not a major concern.&lt;/li&gt;
&lt;li&gt;QoS 2 - &amp;quot;Exactly once&amp;quot;: This guarantees the message is delivered exactly once—no duplicates, no omissions. It&#39;s the best choice for mission-critical applications where data integrity is paramount.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, some other protocols like AMQP or Kafka also provide reliability guarantees, but they tend to be more complex and come with heavier infrastructure requirements. MQTT, on the other hand, offers a simple and lightweight design while still giving you just the right level of reliability for most IIoT scenarios. You can scale your network with ease, all while maintaining a high standard of reliability in your data flows.&lt;/p&gt;
&lt;p&gt;MQTT is the ideal broker for a UNS in IIoT environments, offering real-time, low-latency communication through its Publish-Subscribe model. With Quality of Service (QoS) options for reliable data delivery, it balances performance, scalability, and simplicity. MQTT’s lightweight design makes it perfect for handling large-scale, mission-critical data flows without the complexity of heavier protocols.&lt;/p&gt;
&lt;p&gt;In Part 2, we will explore MQTT&#39;s scalability, topic organization, and wide connectivity providing even more compelling reasons why it is the ultimate choice for UNS brokers.&lt;/p&gt;
&lt;p&gt;If you&#39;re looking to build your own UNS with MQTT, check out our step-by-step &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Article on Building UNS with FlowFuse&lt;/a&gt;. Plus, we&#39;ve made it even easier by offering a built-in MQTT broker service within the FlowFuse Platform, allowing you to manage all your MQTT clients, devices, services, and data from a single, centralized interface. Check it out &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta%20mqtt%20announcement&amp;amp;utm_term=high_intent&amp;amp;utm_content=MQTT%3A%20The%20Frontrunner%20for%20Your%20UNS%20Broker%20-%20Part%201/&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/</id>
        <title>FlowFuse Cloud now available for free!</title>
        <summary>With our new FlowFuse release, comes a new team tier, available on FlowFuse Cloud, to provide you an easy way to manage your many Node-RED instances.</summary>
        <updated>2024-12-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The new Free plan on FlowFuse Cloud will allow you to manage two remote instances using FlowFuse Device Agent, completely free of charge, forever! The new plan also provides Device Auto Snapshots, so any changes to your Node-RED flows running on your devices are backed up automatically.&lt;/p&gt;
&lt;p&gt;FlowFuse is an industrial data platform that enables engineers to build, manage, scale, and secure their Node-RED solutions for digitalizing processes and operations. More fundamentally though, it&#39;s a great platform to manage multiple instances of Node-RED.&lt;/p&gt;
&lt;div class=&quot;blog-update-notes&quot;&gt;
    &lt;p&gt;After careful consideration, we&#39;ve decided to withdraw the free plan. You can still sign up for a 2 week trial to experience all that FlowFuse has to offer, or try out our Starter plan for $20/month.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what&#39;s-included%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#what&#39;s-included%3F&quot;&gt;What&#39;s Included?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whether you&#39;re running multiple Node-RED instances at home for Home Automation, or running thousands of Node-RED instances in your factory, FlowFuse provides an easy-to-use, centralised view of your Node-RED instances, making it easy to manage and monitor them in one place.&lt;/p&gt;
&lt;p&gt;In our new free tier on FlowFuse Cloud you get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 x Remote Node-RED Instances, managed through the FlowFuse &lt;a href=&quot;https://flowfuse.com/docs/device-agent/quickstart/&quot;&gt;Device Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Version control for your Node-RED flows with FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/#introduction&quot;&gt;Snapshots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Remote access to your Node-RED instances through FlowFuse Cloud, utilizing the Device Agent&#39;s &lt;a href=&quot;https://flowfuse.com/docs/device-agent/quickstart/#developer-mode&quot;&gt;Developer Mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;create-your-free-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#create-your-free-team&quot;&gt;Create Your Free Team&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To create a free team, simply &lt;a href=&quot;https://app.flowfuse.com/create&quot;&gt;sign up to FlowFuse Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you&#39;ve filled in your details, you&#39;ll be presented with the option to choose your team type. Select the &amp;quot;Free&amp;quot; option, and you&#39;re good to go.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/onboarding-team-type.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the UI for selecting your Team&#39;s type, when onboarding through on FlowFuse Cloud.&lt;/em&gt;&lt;/p&gt;
&lt;!-- &lt;img width=&quot;438&quot; alt=&quot;image&quot; src=&quot;https://github.com/user-attachments/assets/da6fde55-27bc-42d7-afcc-19235661b558&quot; /&gt; --&gt;
&lt;h3 id=&quot;remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#remote-instances&quot;&gt;Remote Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you create a Free team, an Application is created for you automatically. Applications in FlowFuse help you organise and group your resources, from Instances to DevOps Pipelines and Snapshots for Version Control. Within your new application, you can &amp;quot;register&amp;quot; your first Remote Instance.&lt;/p&gt;
&lt;p&gt;A &amp;quot;Remote Instance&amp;quot; in FlowFuse is a just a term for an instance Node-RED, managed by FlowFuse, but running somewhere different from FlowFuse, e.g. on Edge hardware in a factory or your home. FlowFuse connects to these Remote Instances using the FlowFuse Device Agent, which is easy to setup and get running.&lt;/p&gt;
&lt;p&gt;To get started with your Remote Instance, you need to complete two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Install Device Agent&lt;/strong&gt;: The FlowFuse Device Agent is installed onto the hardware where you want your Node-RED Instance to run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add Your Remote Instance&lt;/strong&gt;: In the FlowFuse UI, add a new &amp;quot;Remote Instance&amp;quot;, and connect to your hardware.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;install-device-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#install-device-agent&quot;&gt;Install Device Agent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Firstly, wherever you want your Node-RED to run, e.g. on a Raspberry Pi or your own Laptop, install the &lt;code&gt;flowfuse-device-agent&lt;/code&gt; package:&lt;/p&gt;
&lt;h4 id=&quot;linux%2Fmacos&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#linux%2Fmacos&quot;&gt;Linux/MacOS&lt;/a&gt;&lt;/h4&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-82&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-82&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @flowfuse/device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-82&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;windows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#windows&quot;&gt;Windows&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Issue the below command in an elevated command prompt:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-89&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-89&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @flowfuse/device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-89&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;For alternative installation options and more details, please refer to our &lt;a href=&quot;https://flowfuse.com/docs/device-agent/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;connect-your-hardware-to-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#connect-your-hardware-to-flowfuse&quot;&gt;Connect Your Hardware to FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To connect your Device Agent, in the FlowFuse Platform, click on the &amp;quot;Remote Instances&amp;quot; option in the left-hand menu, and then click the &amp;quot;Add Remote Instance&amp;quot; button.&lt;/p&gt;
&lt;p&gt;Fill out the name, device type and select the application you&#39;ve just created, and you&#39;ll be presented with the following:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the dialog with the one-time-code to connect your remote Node_RED instance to FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/onboarding-device-registration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the dialog with the one-time-code to connect your remote Node_RED instance to FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The command presented is used to connect your device to FlowFuse. Run this where you just installed the &lt;code&gt;@flowfuse/device-agent&lt;/code&gt; package. This will connect your remote Node-RED instance to the FlowFuse platform.&lt;/p&gt;
&lt;p&gt;The final step to take is to then start running the device agent, which you can do by simply calling:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-111&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-111&quot; class=&quot;language-bash&quot;&gt;flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-111&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;developing-on-your-remote-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#developing-on-your-remote-instance&quot;&gt;Developing on your Remote Instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse offers remote development capabilities, allowing you to edit your Node-RED flows directly, and securely, from the FlowFuse Cloud platform. This is done through &amp;quot;Developer Mode&amp;quot;.&lt;/p&gt;
&lt;p&gt;To get started with developing flows with your Remote Instance, simply select your newly created Instance in the FlowFuse UI, toggle on &#39;Developer Mode&amp;quot;, and click &amp;quot;Open Editor&amp;quot;!&lt;/p&gt;
&lt;h3 id=&quot;version-control-with-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#version-control-with-snapshots&quot;&gt;Version Control with Snapshots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse makes version control easy with &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/#introduction&quot;&gt;Snapshots&lt;/a&gt;. The new Free plan includes Device Auto Snapshots, which will automatically create a snapshot any time a flow is deployed to your device.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#what-else-is-new%3F&quot;&gt;What Else is New?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to the Free plan, we&#39;ve also added two new views to the FlowFuse platform:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pipelines&lt;/strong&gt;: This view provides a way to manage all of your DevOps Pipelines, making it even easier to manage your development, testing, staging and production environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bill of Materials&lt;/strong&gt;: This view provides a way to manage all of your Node-RED dependencies, making it easy to see what versions of nodes are being used across all of your Node-RED instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a full list of everything that went into our 2.12 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.12.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-release-2-12/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/</id>
        <title>Data Modeling: The Key to a Successful Unified Namespace</title>
        <summary>Why data modeling is key to making your Unified Namespace work effectively.</summary>
        <updated>2024-12-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In manufacturing, data flows from various sources—machines, sensors, enterprise systems, and more. A &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt; brings all this data into a central hub. However, centralizing data isn&#39;t enough to truly call it a UNS. It&#39;s not just about aggregating information. A true UNS goes beyond being a data repository; it organizes, structures, and contextualizes that data, transforming it into something valuable and actionable for your business.&lt;/p&gt;
&lt;p&gt;By applying a solid data model, you can turn scattered, unstructured data into a cohesive, meaningful system that supports better decision-making and drives operational improvements. Let&#39;s explore what data modeling is, why it is crucial for making your UNS function effectively, and how it turns scattered data into valuable insights.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;At its core, &lt;strong&gt;data modeling&lt;/strong&gt; is designing how data will be structured, organized, and stored within the UNS. It’s about creating a blueprint or framework that defines the relationships between different data points, ensuring they’re logically structured, easily accessible, and aligned with the business&#39;s needs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A solid data model forms the foundation for understanding and using data effectively. It addresses essential questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How should data be represented?&lt;/strong&gt; – What formats, units, or categories should be used to express the data?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When is it captured, and what does it represent?&lt;/strong&gt; – Is it sensor data, performance metrics, or supply chain information? When was it recorded, and what is its context?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The data model can vary significantly from business to business, depending on the use case. For example, in manufacturing, if a device is sending sensor metrics to a UNS, the data could look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-27&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-27&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-09-19T12:33:46.6035772+02:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;machineId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;press_001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;XYZ Corp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MPX-5000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;sensors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vibration&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mm/s&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pressure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bar&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-27&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, a simpler model might look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-31&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-31&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-09-19T12:33:46+02:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;machine&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;press_001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;vibration&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mm/s&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;pressure&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bar&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-31&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;In both examples, the data is structured with critical elements like timestamps, machine identifiers, sensor readings, and units of measurement. The crucial difference between the two models lies in the level of detail, but both demonstrate how a well-defined data modeling adds immediate value. Organizing data clearly and consistently ensures its accuracy and enables it to be easily analyzed, integrated, and acted upon.&lt;/p&gt;
&lt;p&gt;Now that you have a basic understanding of what data modeling is Let’s take a deep dive into why data modeling is essential to unlocking the full potential of your UNS:&lt;/p&gt;
&lt;h3 id=&quot;1.-ensures-data-consistency-and-standardization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#1.-ensures-data-consistency-and-standardization&quot;&gt;1. Ensures Data Consistency and Standardization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, data is generated from various sources in manufacturing, including machines, sensors, ERP systems, and inventory management tools. Each source may provide data in different formats, units of measurement, or naming conventions.&lt;/p&gt;
&lt;p&gt;For example, one machine might report temperature in Celsius, while another uses Fahrenheit. Some systems might track production rates in pieces per hour, while others use units per minute. These inconsistencies can create confusion and lead to errors in a computerized structure.&lt;/p&gt;
&lt;p&gt;Data modeling addresses this issue by establishing clear standards for how data should be structured and labeled. It ensures uniform temperature, unit, and measurement formats across all systems. For example, a data model might require recording all temperature readings in Celsius and production rates in pieces per hour. This consistency simplifies data analysis from diverse sources and ensures that the system functions reliably and accurately.&lt;/p&gt;
&lt;h3 id=&quot;2.-gives-data-meaning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#2.-gives-data-meaning&quot;&gt;2. Gives Data Meaning&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Raw data on its own is just numbers—isolated and incomplete. For example, a temperature reading of 72.4°C or a vibration level of 1.5 mm/s doesn’t tell much without the proper context. This is where data modeling truly adds value. A data model turns simple measurements into meaningful insights by organizing data that includes critical details like timestamps, data sources, and relationships between data points.&lt;/p&gt;
&lt;p&gt;Contextualizing data means understanding when it was captured, where it came from, and what it’s related to. A timestamp helps track trends over time, such as detecting a gradual temperature rise that could signal an issue before it becomes critical. Knowing the data source—whether it’s a specific machine or sensor—enables targeted troubleshooting and ensures that the right teams are working with the right data. Data modeling also links data points, like correlating vibration and temperature readings, to identify potential equipment failures. This structure makes data far more accessible and actionable, allowing teams to make informed, real-time decisions, prevent unplanned downtime, and drive process improvements.&lt;/p&gt;
&lt;p&gt;In summary, data modeling transforms raw data into actionable insights, helping you understand what is happening in your operation, when it started, where it is occurring, and how to address it effectively.&lt;/p&gt;
&lt;h3 id=&quot;3.-facilitates-data-interoperability-and-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#3.-facilitates-data-interoperability-and-integration&quot;&gt;3. Facilitates Data Interoperability and Integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In manufacturing, various devices and systems generate data in different formats and use distinct communication protocols, making integrating and utilizing this data effectively challenging.&lt;/p&gt;
&lt;p&gt;For example, PLCs may use one protocol, while SCADA systems or MES may rely on entirely different ones. This lack of consistency complicates consolidating data and extracting meaningful insights. Integrating other systems often requires addressing discrepancies in how data is structured and labeled. For instance, multiple sensors on a production line might send data in various formats or label the same metric differently. One sensor might label temperature as &amp;quot;temp,&amp;quot; another as &amp;quot;temperature,&amp;quot; and yet another as &amp;quot;T1.&amp;quot; These inconsistencies can lead to errors or failures in integrated systems, such as monitoring tools that depend on consistent data labeling to function correctly.&lt;/p&gt;
&lt;p&gt;This is where data modeling becomes essential. It creates a standard structure for organizing and labeling data, ensuring that different systems can &amp;quot;speak the same language&amp;quot; and integrate seamlessly.&lt;/p&gt;
&lt;p&gt;For example, in a predictive maintenance system, sensor data such as temperature and vibration can be used to predict potential machine failures. With the right data model, this sensor data can be directly linked to your CMMS (Computerized Maintenance Management System), regardless of how many sensors are involved or added over time. Since engineers understand the standardized data structure, they can easily integrate the CMMS with minimal effort. This integration automatically triggers maintenance alerts and work orders, helping to prevent downtime without requiring manual intervention.&lt;/p&gt;
&lt;h3 id=&quot;4.-enables-easy-access-and-time-savings&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#4.-enables-easy-access-and-time-savings&quot;&gt;4. Enables Easy Access and Time Savings&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Disorganized data wastes time and resources in manufacturing. A transparent data model makes essential information easy for troubleshooting, performance checks, and decision-making tasks.&lt;/p&gt;
&lt;p&gt;With a standardized system, figuring out confusing labels or complex data is unnecessary. A consistent data model organizes information, helping operators respond faster, reduce downtime, and minimize errors.&lt;/p&gt;
&lt;p&gt;Quick access to accurate data speeds up decision-making, cuts downtime, and improves efficiency, leading to cost savings.&lt;/p&gt;
&lt;h3 id=&quot;5.-scalability-and-continuous-improvement&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#5.-scalability-and-continuous-improvement&quot;&gt;5. Scalability and Continuous Improvement&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A well-structured data model serves the needs of your current manufacturing operations and lays the groundwork for future growth and continuous improvement. As your production processes evolve or new technologies and data sources come online, a good data model allows your UNS to adapt without disrupting existing systems.&lt;/p&gt;
&lt;p&gt;For example, as you add new machines, automated production lines, or advanced sensors to your operations, the data model ensures that these new elements integrate smoothly into the existing framework. It maintains consistency, enabling new data points to be mapped easily while keeping the system organized and efficient.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 3px solid rgba(173, 192, 252, 0.55); opacity: 0.3; margin-bottom: 20px;&quot; /&gt;
&lt;p&gt;With all these benefits in mind, the next step is to consider how to implement data modeling effectively. Data modeling is a much deeper, more dynamic process that can reshape how you use data across your entire business. It&#39;s not only about structuring and integrating data but also about transforming your operations, unlocking new efficiencies, and driving growth. The right platform can help you go beyond essential organization and truly harness the power of your data.&lt;/p&gt;
&lt;h2 id=&quot;leverage-flowfuse-for-effective-data-modeling-in-your-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/why-uns-need-data-modeling/#leverage-flowfuse-for-effective-data-modeling-in-your-uns&quot;&gt;Leverage FlowFuse for Effective Data Modeling in Your UNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; makes building and managing a Unified Namespace (UNS) simple and efficient. It connects IT and OT systems, streamlines workflows, and transforms raw data into meaningful insights. With FlowFuse, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Connect&lt;/strong&gt;: Integrate various services, hardware, and APIs effortlessly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collect&lt;/strong&gt;: Aggregate data from machines, sensors, and other sources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transform&lt;/strong&gt;: Easily standardize and add context to raw data, making it more meaningful and usable across your systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualize&lt;/strong&gt;: Create dashboards with a low-code approach to monitor and analyze your operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learn how to build your UNS in just 15 minutes with &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;FlowFuse uses Node-RED, an open-source low-code platform, to turn unstructured data into organized, actionable models. Its ability to transform and contextualize data ensures consistency and clarity, helping you get the most value from your data.&lt;/p&gt;
&lt;p&gt;With support for over 5,000 community nodes and protocols like MQTT, OPC-UA, and Modbus, FlowFuse simplifies connecting systems and unifying data.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/&quot;&gt;this article&lt;/a&gt; to see how FlowFuse makes data modeling easier.&lt;/p&gt;
&lt;p&gt;FlowFuse also offers enterprise-grade features to manage edge devices and Node-RED instances, helping you scale, collaborate, and stay compliant.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/</id>
        <title>Streamlining Node-RED Collaboration with FlowFuse</title>
        <summary>Enabling Real-Time Collaboration in Industrial Environments with FlowFuse</summary>
        <updated>2024-12-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A few weeks ago, we discussed how &lt;a href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/&quot;&gt;FlowFuse centralizes edge device and Node-RED management&lt;/a&gt;, as well as its &lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/&quot;&gt;security features&lt;/a&gt;. Now, we&#39;re focusing on another key benefit of FlowFuse—making collaboration easier for teams in industrial environments.&lt;/p&gt;
&lt;p&gt;As more manufacturing companies use FlowFuse for edge device management, data pipelines, and bridging IT-OT systems, the platform is becoming a key tool for handling complex data operations. Collaboration is critical in manufacturing environments with thousands of devices and data flows. FlowFuse accelerates industrial data operations by simplifying real-time collaboration while ensuring security and scalability.&lt;/p&gt;
&lt;p&gt;Now, let’s look at how FlowFuse makes collaboration effortless. With features like centralized management, real-time updates, and easy sharing, FlowFuse helps teams stay on the same page—whether working on the same flow or across multiple projects. The platform eliminates the usual pain points of collaboration, allowing teams to quickly deploy, modify, and scale Node-RED solutions confidently while maintaining control and security.&lt;/p&gt;
&lt;h2 id=&quot;laying-the-foundation-for-better-collaboration-with-centralization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#laying-the-foundation-for-better-collaboration-with-centralization&quot;&gt;Laying the Foundation for Better Collaboration with Centralization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Effective collaboration starts with everyone having access to the same interface and information. When team members work with different versions of flows or data, things can easily get out of sync, making collaboration difficult.&lt;/p&gt;
&lt;p&gt;This is exactly why centralized management is so crucial. With FlowFuse, everything—your Node-RED Instances, edge devices, settings, and data—is in one place. Everyone on your team sees the same interface, accesses the same up-to-date information, and works from the same set of resources. There’s no more hunting for the correct version or trying to sync up tools.&lt;/p&gt;
&lt;p&gt;Everything in one place means fewer mistakes, fewer mix-ups, and much easier collaboration. Whether you&#39;re working in a single instance or managing a whole network of edge devices, FlowFuse makes it easy to stay aligned. You can move quickly and confidently without worrying about missing something important.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;List of all Node-RED instances organized centrally within your team.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/application-wise-instance-organization.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A centralized view of applications with Node-RED instances organized under each application for easier management.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;List of all Node-RED instances organized centrally within your team.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/list-of-instances.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A list of all Node-RED instances is displayed centrally, allowing team members to manage and access them easily.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;All edge devices centralized for easy management.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edge-devices.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A centralized view of edge devices, providing streamlined management for all devices within the platform.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In short, centralization makes everything simpler. It’s the backbone of effective teamwork, ensuring everyone works from the same starting point. With FlowFuse, you don&#39;t have to worry about syncing — everything&#39;s already in sync for you.&lt;/p&gt;
&lt;p&gt;If you want to dive deeper into how FlowFuse centralizes things, check out this article: &lt;a href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/&quot;&gt;Managing Node-RED Instances in a Centralized Platform&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;creating-and-managing-teams&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#creating-and-managing-teams&quot;&gt;Creating and Managing Teams&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Collaboration begins with the right team setup. In FlowFuse, you can quickly &lt;a href=&quot;https://flowfuse.com/docs/user/team/#creating-a-new-team&quot;&gt;create a team&lt;/a&gt; and assign it a name. Once your team is set up, you can easily &lt;a href=&quot;https://flowfuse.com/docs/user/team/#adding-team-members&quot;&gt;invite members to join&lt;/a&gt;. As mentioned earlier, all your Node-RED instances, edge devices, configurations, settings, and data are organized and centralized within that team.&lt;/p&gt;
&lt;p&gt;However, simply creating a team and inviting members isn’t enough. Not all team members need access to all information, features, or controls. It’s essential to ensure that the right people have the right level of access to do their work effectively. Providing excessive access to members who don’t require it or who might lack the necessary expertise can lead to accidental changes or mistakes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Invite new members to your FlowFuse team by assigning roles and permissions.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/inviting-member-to-team.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A centralized view of edge devices, providing streamlined management for all devices within the platform.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse team management interface displaying team members and their roles for streamlined collaboration control.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/team-members-list.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A comprehensive list of team members with assigned roles and permissions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;FlowFuse’s Role-Based Access Control (RBAC)&lt;/a&gt; comes in. When inviting new team members, you can assign them specific roles, each with different permissions and access scopes. This ensures that each team member has the appropriate level of access based on their role, reducing the risk of unintended changes or disruptions.&lt;/p&gt;
&lt;p&gt;You can later update roles to adjust permissions as your team, and projects evolve if needed. FlowFuse’s RBAC helps maintain control and security while empowering each team member to contribute effectively to the project.&lt;/p&gt;
&lt;h2 id=&quot;real-time-collaboration-and-monitoring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#real-time-collaboration-and-monitoring&quot;&gt;Real-Time Collaboration and Monitoring&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once team members have been invited, Node-RED instances have been created, and edge devices have been added by the team owner, FlowFuse&#39;s real-time collaboration capabilities come into play. Team members, whether they have owner or member roles, can work on the same project simultaneously. They can update flows, deploy them, and monitor real-time progress.&lt;/p&gt;
&lt;p&gt;With FlowFuse, tracking who is working on which project and at what stage is easy. The platform lets you see who has opened the Node-RED editor you are working on, which flow they are working on, and even which specific node they are interacting with. This visibility ensures that team members are always aligned and that collaboration happens seamlessly without stepping on each other’s toes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot showing multiple users working on the same Node-RED flow in real time within FlowFuse, with live updates and visibility of each user&#39;s actions.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multiplayer-flowfuse.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Multiple users collaborate on the same Node-RED flow in real-time within FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For instance, if two members modify different parts of the same flow, they can do so without interrupting each other’s work. They’ll both be able to see each other&#39;s updates in real-time, ensuring the project moves forward smoothly. This collaborative approach enhances teamwork and helps avoid mistakes, as everyone has the information they need when needed.&lt;/p&gt;
&lt;p&gt;In addition, FlowFuse’s real-time monitoring features allow you to track the status of edge devices, Node-RED instances, and overall system health. You can also monitor Node-RED logs for troubleshooting, ensuring no issue slips through the cracks as your team works together efficiently.&lt;/p&gt;
&lt;h2 id=&quot;version-controlling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#version-controlling&quot;&gt;Version Controlling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In any collaborative environment, accidental changes or conflicts are inevitable, especially when multiple team members are working on the same project. While collaboration is essential for progress, the ability to track changes, roll back versions, and understand who made what updates is critical for maintaining control and continuity.&lt;/p&gt;
&lt;p&gt;FlowFuse provides robust version control features that make it easier to manage changes across your Node-RED flows. Whether you revert to a previous version of a flow, roll back accidental changes, or track updates over time, FlowFuse ensures that you never lose critical work.&lt;/p&gt;
&lt;p&gt;To view the version history, navigate to your Node-RED Instance view and switch to the &#39;Version History&#39; tab. Here, you’ll find two key sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Timeline: This section displays a timeline of who deployed, what is updated, and for which flow and when. Each deployment automatically creates a snapshot of your Node-RED instance. You can easily roll back to any previous version by clicking the three-dot icon on the right and selecting Restore Snapshot. You also have the option to compare the current version of your Node-RED instance with previous snapshots, download it, and more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot displaying the version history timeline in FlowFuse, showing deployment snapshots and the ability to track and roll back changes in Node-RED instances.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/version-history-timeline.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A version history timeline shows deployment and changes made in flows, making it easy to track updates and revert to previous versions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Snapshots: The second tab, Snapshots, provides a clean, list-style interface that shows all available snapshots. Unlike the timeline view, this section focuses solely on snapshots without the detailed deployment history. You can upload or download snapshots and even create a snapshot of your instance at any time by clicking the Create Snapshot button.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot of the snapshots interface in FlowFuse, showing a list of available snapshots that can be restored or compared.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/version-history-snapshots.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The snapshots list interface in FlowFuse provides an organized view of all available snapshots for easy restoration or comparison.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This version control functionality allows you to manage and recover Node-RED instances seamlessly, ensuring that your team can collaborate effectively without the risk of losing or overwriting important work.&lt;/p&gt;
&lt;h2 id=&quot;shared-flow-library&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#shared-flow-library&quot;&gt;Shared Flow Library&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When working on projects, it&#39;s common to develop reusable flows that can save time and effort for the entire team. For example, you might create a flow to calculate Overall Equipment Efficiency (OEE) or other valuable flows that can be reused across multiple projects.&lt;/p&gt;
&lt;p&gt;FlowFuse makes this process easy with the &lt;a href=&quot;https://flowfuse.com/docs/user/shared-library/&quot;&gt;Shared Flow Library&lt;/a&gt;. This feature allows owners and members to export significant flows and store them in a shared library, making them available to all team members. Once a flow is added to the library, anyone within the same team can import and use it in any Node-RED instance whenever needed.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot of the Shared Flow Library in FlowFuse, showing a list of flows available for import and reuse by team members in any Node-RED instance.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/shared-lib-import.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Shared Flow Library in FlowFuse displays a list of reusable flows that team members can import and use across multiple Node-RED instances.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This shared approach streamlines development, eliminates redundant work, and ensures project consistency, ultimately saving time. Whether it’s a reusable function, a typical configuration, or a flow for recurring tasks, FlowFuse’s Shared Flow Library enables your team to easily access and integrate these resources, boosting productivity and fostering better collaboration.&lt;/p&gt;
&lt;h2 id=&quot;audit-logs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#audit-logs&quot;&gt;Audit Logs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Accountability is essential when multiple team members collaborate on complex industrial projects. FlowFuse offers comprehensive Audit Logs to track every action taken within the platform. This feature provides a detailed record of who made which changes, when those changes were made, and the specifics of each action.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A screenshot of the audit logs in FlowFuse, displaying detailed records of changes made by users, ensuring accountability and security within the platform.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/application-audit-logs.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Audit logs in FlowFuse, tracking every action taken within the platform to ensure accountability and transparency among team members.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With Audit Logs, you can easily trace who deployed a flow, modified settings, or interacted with assets. This transparency ensures that all team members are accountable for their actions, enhancing security and reducing the risk of errors or unauthorized changes.&lt;/p&gt;
&lt;p&gt;Audit Logs are especially valuable for troubleshooting. They allow you to pinpoint when issues arise and identify who made changes that could have contributed to the problem, providing crucial context for resolution.&lt;/p&gt;
&lt;p&gt;For more information on using Audit Logs effectively, refer to our documentation on &lt;a href=&quot;https://flowfuse.com/docs/user/logs/#audit-log&quot;&gt;Audit Logs in FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are just a few of the features we’ve covered. FlowFuse has many more tools and capabilities that can further enhance collaboration, streamline workflows, and optimize your industrial operations.&lt;/p&gt;
&lt;p&gt;In summary, FlowFuse is a platform that streamlines collaboration on Node-RED projects. Centralizing your Node-RED instances, devices, and data ensures that everyone on your team is aligned and has access to the same resources. Features like real-time updates, role-based access, version control, and audit logs make collaborating easier, staying secure, and avoiding errors easier. Whether you&#39;re managing small flows or large-scale industrial systems, FlowFuse helps your team work together more efficiently and effectively.&lt;/p&gt;
&lt;p&gt;With FlowFuse, factories can achieve faster, safer, and more scalable collaboration on data pipelines, edge device management, and IT-OT integration.&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/flowfuse-team-collaboration/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Explore more resources and deepen your understanding of FlowFuse with these articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/&quot;&gt;Managing Node-RED Instances in a Centralized Platform&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
Learn how to effectively manage Node-RED instances in a centralized environment with FlowFuse, simplifying deployment and ensuring scalability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/&quot;&gt;Exploring FlowFuse Security Features&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
Discover the security tools and features built into FlowFuse to help protect your industrial data and keep your systems secure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/&quot;&gt;Building on FlowFuse: Working with Devices&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
Dive into how FlowFuse supports device management, enabling you to build, deploy, and monitor edge devices more efficiently.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/</id>
        <title>How to Bridge Modbus to MQTT: Step-by-Step Guide</title>
        <summary>Build a Production-Ready Modbus to MQTT Bridge with Node-RED</summary>
        <updated>2024-12-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Converting Modbus to MQTT unlocks the value trapped in legacy industrial equipment. Industrial facilities worldwide face a persistent challenge: their Modbus-based sensors, PLCs, and controllers generate valuable operational data, but that data remains isolated in local control networks, unable to feed modern cloud analytics, remote dashboards, or predictive maintenance systems.&lt;/p&gt;
&lt;p&gt;We&#39;ve built Modbus to MQTT bridges for manufacturing plants ranging from small production lines to enterprise-scale facilities, and the root problem is always the same protocol mismatch. Modbus requires a master-slave architecture with polling—one device requests data, another responds. MQTT enables publish-subscribe messaging—devices push data to a central broker where any authorized application can subscribe. These are fundamentally incompatible communication patterns.&lt;/p&gt;
&lt;p&gt;The proven solution is protocol bridging with Node-RED. This guide shows you how to build a reliable Modbus to MQTT gateway that reads holding registers from your devices, transforms raw sensor readings into human-readable formats, and publishes structured data to a Unified Namespace using FlowFuse&#39;s integrated MQTT broker. You&#39;ll bridge the OT/IT gap and enable cloud integration, real-time monitoring, and data-driven decision-making across your operations.&lt;/p&gt;
&lt;h2 id=&quot;why-bridge-modbus-to-mqtt%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#why-bridge-modbus-to-mqtt%3F&quot;&gt;Why Bridge Modbus to MQTT?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modbus handles local device communication effectively. A PLC polls sensors, reads holding registers, writes control signals—standard automation workflows that have proven reliable for decades. The limitation appears when you need that same data elsewhere: in a cloud database, on a remote dashboard, or feeding a predictive maintenance algorithm.&lt;/p&gt;
&lt;p&gt;The constraint is architectural. Modbus requires a master-slave relationship. One device initiates requests, others respond. You can&#39;t have multiple systems independently accessing the same Modbus device without coordination, and you can&#39;t push data—only pull it through polling. This creates the operational technology (OT) and information technology (IT) integration gap.&lt;/p&gt;
&lt;p&gt;MQTT removes these constraints through its broker-based architecture. Devices publish data once to the broker. Any authorized system—whether on-premises or cloud-based—subscribes to relevant topics and receives updates. No polling loops, no master-slave coordination, no point-to-point connections to manage.&lt;/p&gt;
&lt;p&gt;This is where the &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Unified Namespace&lt;/a&gt; concept becomes practical. Instead of data scattered across disconnected Modbus networks, PLCs, and SCADA systems, you establish a single MQTT broker as the central data hub. All operational data flows through standardized topics organized by facility hierarchy: &lt;code&gt;enterprise/site/area/line/equipment&lt;/code&gt;. Applications consume what they need through subscriptions.&lt;/p&gt;
&lt;p&gt;Consider a production line running legacy Modbus equipment—VFDs controlling motor speeds, pressure transmitters monitoring hydraulic systems, temperature sensors on critical bearings. Historically, this data stays within the local control network. Bridge it to MQTT, and suddenly the maintenance team accesses real-time vibration data on their tablets, the operations dashboard displays line efficiency metrics, and the cloud analytics platform builds predictive models from historical trends—all from the same data stream.&lt;/p&gt;
&lt;p&gt;FlowFuse provides both the Node-RED runtime for building these bridges and the MQTT broker infrastructure for the Unified Namespace. The integration is straightforward: Node-RED flows poll Modbus devices and publish to FlowFuse&#39;s MQTT broker, where any authorized application can subscribe.&lt;/p&gt;
&lt;h2 id=&quot;how-to-bridge-modbus-to-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#how-to-bridge-modbus-to-mqtt&quot;&gt;How to Bridge Modbus to MQTT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s look at the steps to bridge Modbus data to MQTT using FlowFuse, leveraging Node-RED&#39;s capabilities. The process involves retrieving data from a Modbus device (For Practical example, we are using OpenSim to simulate Modbus data), transforming and processing the data (e.g., scaling raw sensor data into human-readable formats), and sending it to your Unified Namespace.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Bridging Modbus Data to MQTT using Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/bridging-modbus-data-to-mqtt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Bridging Modbus Data to MQTT using Node-RED&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modbus data source&lt;/strong&gt;: An actual Modbus device or a simulator like ModSim.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Instance&lt;/strong&gt;: The easiest and production-ready option is FlowFuse—run Node-RED on edge devices, manage and build flows remotely with your team. Deploy, scale, and secure hundreds or thousands of instances with built-in team collaboration, version control, and production-grade features. &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;Sign up here&lt;/a&gt; and follow &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;this guide to run Node-RED with FlowFuse on your edge device&lt;/a&gt;. Alternatively, install Node-RED locally on hardware with access to your Modbus network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQTT Broker&lt;/strong&gt;: You need broker connection details (host, port, credentials). If you&#39;re using FlowFuse Pro or Enterprise, there&#39;s an integrated broker at &lt;code&gt;broker.flowfuse.cloud&lt;/code&gt;—just create a client in the platform and you&#39;re done.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1%3A-collect-data-from-modbus-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#step-1%3A-collect-data-from-modbus-devices&quot;&gt;Step 1: Collect Data from Modbus Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step is to collect data from your Modbus devices. To do this, you&#39;ll need to run Node-RED on your Device. If your Modbus device communicates via a serial port, Node-RED will need access to that port, which you can manage with the appropriate configuration. If you&#39;re using Modbus TCP and both Node-RED and your Modbus device are on the same network, the connection is straightforward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1.1: Running the FlowFuse device agent on your edge device&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To run Node-RED on your edge device with just a few simple steps, you can use the &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;FlowFuse Device Agent&lt;/a&gt;. This allows you to run Node-RED locally and also connect it to FlowFuse Cloud for remote monitoring and management, making it easier to keep track of your devices and workflows from anywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1.2: Install Modbus Nodes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While Node-RED doesn&#39;t include Modbus nodes by default, adding them to your palette is simple. Installing the necessary Modbus nodes from the Node-RED library will enable communication with your Modbus devices, whether they’re connected via serial or TCP. This step ensures you can start reading data from your Modbus devices and processing it for further integration.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Palette Manager&lt;/strong&gt; by clicking the menu icon in the top-right corner of Node-RED and selecting &lt;strong&gt;Palette Manager&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the Palette Manager, search for &lt;code&gt;node-red-contrib-modbus&lt;/code&gt; in the search bar.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; to add the Modbus nodes to your Node-RED environment.&lt;/li&gt;
&lt;li&gt;Once installed, the nodes appear in the left-side palette under the &lt;strong&gt;Modbus&lt;/strong&gt; category. These nodes will allow you to interact with Modbus devices in your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 1.3: Configure the Modbus Connection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Next, you&#39;ll need to configure the Modbus connection based on your device type. Modbus devices can communicate using two primary protocols: &lt;strong&gt;Modbus RTU&lt;/strong&gt; (over serial) or &lt;strong&gt;Modbus TCP&lt;/strong&gt; (over Ethernet/Wi-Fi). The specific choice depends on the type of Device you are working with.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Modbus Read&lt;/strong&gt; node onto your Node-RED Canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the &lt;strong&gt;Modbus Read&lt;/strong&gt; node to open its configuration.&lt;/li&gt;
&lt;li&gt;In the configuration window:
&lt;ul&gt;
&lt;li&gt;Enter the &lt;strong&gt;Unit ID&lt;/strong&gt; (this is the device address, typically &lt;strong&gt;1&lt;/strong&gt;, but it may vary depending on your device).&lt;/li&gt;
&lt;li&gt;Choose the &lt;strong&gt;Function&lt;/strong&gt; you need, such as &lt;strong&gt;Read Holding Registers&lt;/strong&gt;, &lt;strong&gt;Read Input Registers&lt;/strong&gt;, etc. (this depends on the type of data you want to read).&lt;/li&gt;
&lt;li&gt;Specify the &lt;strong&gt;Start Address&lt;/strong&gt; (the address of the first register you want to start reading).&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Quantity&lt;/strong&gt; (the number of registers to read).&lt;/li&gt;
&lt;li&gt;Specify the &lt;strong&gt;Poll Rate&lt;/strong&gt; (e.g., how often you want to collect data, such as every 1 second).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Server&lt;/strong&gt; field, click the &lt;strong&gt;+&lt;/strong&gt; button to add a new Modbus server, and select the type.
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;Modbus TCP&lt;/strong&gt;: Enter the &lt;strong&gt;IP address&lt;/strong&gt; and &lt;strong&gt;Port&lt;/strong&gt; (the default Modbus TCP port is &lt;strong&gt;502&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Modbus RTU&lt;/strong&gt;: If you&#39;re using a serial connection, you&#39;ll need to specify the serial port (such as &lt;code&gt;/dev/ttyUSB0&lt;/code&gt; on Linux or &lt;code&gt;COM1&lt;/code&gt; on Windows), as well as the baud rate and other serial settings.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Unit ID&lt;/strong&gt; (again, this should match the Unit ID you entered earlier).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing Modbus node configuration for reading holding registers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-connection-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing Modbus node configuration for reading holding registers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing Modbus client node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modbus-connection-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing Modbus client node configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Once the connection details are filled in, click &lt;strong&gt;Add&lt;/strong&gt; to save the configuration, then click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 1.4: Test the Modbus Connection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After configuring the connection, it&#39;s time to test the data collection.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;Modbus Read&lt;/strong&gt; node&#39;s output to to the input of &lt;strong&gt;Debug&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; in the top-right corner of Node-RED to deploy your flow.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Debug Panel&lt;/strong&gt; on the right side of the Node-RED interface. If the connection is successful, you should see the raw data from your Modbus device in the Debug Panel.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If no data appears, check the connection settings (IP address, Unit ID, port, etc.) and ensure your Modbus device is correctly configured and accessible. If you use a simulator like ModSim, ensure it’s running and properly configured to send data.&lt;/p&gt;
&lt;p&gt;For more information on using Modbus with Node-RED, please read our tutorial on &lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Using Modbus with Node-RED&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you prefer a video explanation, &lt;a href=&quot;https://www.linkedin.com/in/wago-kurt-braun/&quot;&gt;Kurt Braun&lt;/a&gt; from WAGO demonstrates how to collect Modbus data using Node-RED in FlowFuse:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;PdVdGg__zUM&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;Bridging Modbus to MQTT with Node-RED&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-transforming-modbus-data-for-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#step-2%3A-transforming-modbus-data-for-uns&quot;&gt;Step 2: Transforming Modbus Data for UNS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After collecting data from your Modbus device, the next step is transforming it into a usable format for cloud-based IoT applications. Modbus data typically comes in raw register values, and you may need to convert these values into human-readable formats like temperature, pressure, or other measurements.&lt;/p&gt;
&lt;p&gt;Let&#39;s walk through the transformation process step by step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2.1: Parsing and Converting Raw Modbus Data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Modbus devices often return data in registers that need to be interpreted. For example, a temperature sensor might return a register value like 350, which represents 35.0°C if the sensor stores values in tenths of degrees.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The ModSim interface, generating simulated Modbus data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/modsim.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The ModSim interface, generating simulated Modbus data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here’s an example of the raw Modbus data I am receiving from ModSim: &lt;code&gt;[225, 1013, 29, 50, 603]&lt;/code&gt;. These values represent the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;225&lt;/code&gt;: Temperature (in tenths of degrees, which would be 22.5°C)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1013&lt;/code&gt;: Part 1 of the pressure value (higher register)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;29&lt;/code&gt;: Part 2 of the pressure value (lower register)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;50&lt;/code&gt;: Vibration (in tenths of degrees, which would be 5g)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;603&lt;/code&gt;: Humidity (in tenths of degrees, which would be 60.3%)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We must convert these raw register values into human-readable formats for cloud integration. For instance, we divide the temperature and vibration by 10 to get the actual values in degrees Celsius and g, respectively, and similarly for other parameters like humidity. For pressure, the higher and lower register values are combined to compute the complete value accurately.&lt;/p&gt;
&lt;p&gt;To determine how to process raw Modbus data, such as dividing by a specific value, concatenating, or applying other transformation formulas, refer to the manual of the sensor you use for specific instructions.&lt;/p&gt;
&lt;p&gt;In Node-RED, you can use various nodes for transformation. You can choose the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/function/&quot;&gt;Function node&lt;/a&gt; for advanced processing, the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/change/&quot;&gt;Change node&lt;/a&gt; for simpler operations, or the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/template/&quot;&gt;Template node&lt;/a&gt; for defining schemas. For more complex data parsing scenarios—such as handling multiple data types (floats, 32-bit integers, strings), dealing with big-endian/little-endian conversions, or performing byte swapping—consider using the &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt; node. This specialized node simplifies parsing Modbus buffers into various data formats without writing custom code. Learn more in our guide on &lt;a href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/&quot;&gt;using Buffer Parser for industrial data&lt;/a&gt;. In this article, I will demonstrate a low-code approach using the Change node to process the data cleanly.&lt;/p&gt;
&lt;p&gt;Additionally, for better organization and accessibility, I will send each metric separately and include additional metadata such as the &lt;code&gt;timestamp&lt;/code&gt; and &lt;code&gt;unit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For Temperature&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Set the following in the &lt;strong&gt;Set&lt;/strong&gt; rules:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.data&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.timestamp&lt;/code&gt; to the timestamp function of the Change node.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.value&lt;/code&gt; to &lt;code&gt;data[0] / 10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.unit&lt;/code&gt; to &lt;code&gt;&#39;c&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the Change node rules transforming temperature data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/temperature-data-tranformation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the Change node rules transforming temperature data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;li&gt;Connect the first output of the &lt;strong&gt;Modbus Read&lt;/strong&gt; node to the input of this &lt;strong&gt;Change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;For Pressure&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Set the following in the &lt;strong&gt;Set&lt;/strong&gt; rules:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.data&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.timestamp&lt;/code&gt; to the timestamp function of the Change node.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.value&lt;/code&gt; to &lt;code&gt;$number($string(data[1]) &amp;amp; $string(data[2]))&lt;/code&gt; as a JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.unit&lt;/code&gt; to &lt;code&gt;&#39;ppm&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the Change node rules transforming pressure data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pressure-data-transformation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the Change node rules transforming pressure data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;li&gt;Connect the first output of the &lt;strong&gt;Modbus Read&lt;/strong&gt; node to the input of this &lt;strong&gt;Change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;For Vibration&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Set the following in the &lt;strong&gt;Set&lt;/strong&gt; rules:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.data&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.timestamp&lt;/code&gt; to the timestamp function of the Change node.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.value&lt;/code&gt; to &lt;code&gt;data[3] / 10&lt;/code&gt; as a JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.unit&lt;/code&gt; to &lt;code&gt;&#39;g&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the Change node rules transforming vibration data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/vibration-data-transformation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the Change node rules transforming vibration data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;li&gt;Connect the first output of the &lt;strong&gt;Modbus Read&lt;/strong&gt; node to the input of this &lt;strong&gt;Change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;For Humidity&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Set the following in the &lt;strong&gt;Set&lt;/strong&gt; rules:
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;msg.data&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.timestamp&lt;/code&gt; to the timestamp function of the Change node.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.value&lt;/code&gt; to &lt;code&gt;data[4] / 10&lt;/code&gt; as a JSONata expression.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.unit&lt;/code&gt; to &lt;code&gt;&#39;%&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the Change node rules transforming humidity data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/humidity-data-transformation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the Change node rules transforming humidity data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the configuration.&lt;/li&gt;
&lt;li&gt;Connect the first output of the &lt;strong&gt;Modbus Read&lt;/strong&gt; node to the input of this &lt;strong&gt;Change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you have configured and connected all the Change nodes, add a &lt;strong&gt;Debug&lt;/strong&gt; node to each Change node&#39;s output to verify that the transformed data appears as expected. Deploy the flow, then check the output in the Debug Panel to ensure that each metric is correctly formatted with the appropriate timestamp, value, and unit.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-publishing-modbus-data-to-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/12/publishing-modbus-data-to-uns/#step-3%3A-publishing-modbus-data-to-mqtt&quot;&gt;Step 3: Publishing Modbus Data to MQTT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After transforming the Modbus data into a human-readable format, the next step is to publish it via MQTT to build your Unified Namespace (UNS). The UNS is created by organizing your MQTT topics into a standardized hierarchy—when you publish data to these structured topics, you&#39;re establishing the namespace that other systems can subscribe to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3.1: Preparing Your MQTT Broker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As mentioned in the prerequisites, FlowFuse provides an integrated MQTT broker service for Team and Enterprise users. The broker uses username and password authentication—you create clients on the platform with credentials that control topic access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To create MQTT clients:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the FlowFuse platform and click &lt;strong&gt;Broker&lt;/strong&gt; in the left sidebar.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Create Client&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Enter a &lt;strong&gt;username&lt;/strong&gt; and &lt;strong&gt;password&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt;Configure &lt;strong&gt;topic access control patterns&lt;/strong&gt; if needed, specifying which topics the client can publish to or subscribe from.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save&lt;/strong&gt; to create the client.&lt;/li&gt;
&lt;li&gt;Once saved, copy the &lt;strong&gt;Client ID&lt;/strong&gt; from the client list and save it for the next step.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more details about the FlowFuse MQTT broker service, refer to the &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;MQTT Broker Service Announcement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3.2: Configure MQTT Nodes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now you&#39;ll configure Node-RED to publish your transformed Modbus data to the MQTT broker.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Node-RED editor, drag an &lt;strong&gt;mqtt out&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node, then click the &lt;strong&gt;+&lt;/strong&gt; icon next to the &lt;strong&gt;Server&lt;/strong&gt; field to add a new broker connection:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server&lt;/strong&gt;: Enter &lt;code&gt;broker.flowfuse.cloud&lt;/code&gt; (for FlowFuse MQTT).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port&lt;/strong&gt;: Use the default MQTT port (1883 for non-TLS, 8883 for TLS).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client ID&lt;/strong&gt;: Paste the Client ID you copied earlier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Username&lt;/strong&gt;: Enter the username you created.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Password&lt;/strong&gt;: Enter the password you created.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MQTT broker node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-config-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;MQTT broker node configuration&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to save the broker configuration.&lt;/li&gt;
&lt;li&gt;Back in the mqtt out node configuration:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;: Enter a topic following the ISA-95 equipment hierarchy, such as &lt;code&gt;plant2/Area4/Cell2/DeviceA/temperature&lt;/code&gt;. This naming convention organizes data by enterprise, site, area, line, and equipment, making it easier to filter, manage, and scale your system as it grows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QoS&lt;/strong&gt;: Select the appropriate Quality of Service level:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0&lt;/strong&gt; (At most once) - Fastest, but no delivery guarantee&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1&lt;/strong&gt; (At least once) - Ensures delivery, possible duplicates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; (Exactly once) - Slowest, but guarantees single delivery&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retain&lt;/strong&gt;: Enable this if you want the broker to store the last message for new subscribers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;MQTT Out node configuration for temperature data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-client-config-temperature.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;MQTT Out node configuration for temperature data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This example uses environment variables for sensitive configuration data to prevent accidental exposure when sharing flows. For more information, refer to &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables with Node-RED&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save the node configuration.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;Change&lt;/strong&gt; node (which transforms your temperature data) to the input of this &lt;strong&gt;mqtt out&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Using FlowFuse MQTT Nodes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re using the FlowFuse MQTT broker, FlowFuse provides specialized MQTT nodes that simplify configuration. These nodes automatically configure the broker connection details when you drop them onto the canvas—no manual setup of server address, Client ID, username, or password required. You also won&#39;t need to manually create clients in the broker; they&#39;re automatically created when you use these nodes. This streamlines the development process and reduces configuration errors. Learn more about &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mqtt/&quot;&gt;FlowFuse MQTT nodes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3.3: Configure MQTT Nodes for Remaining Metrics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Repeat the configuration process for each metric (pressure, vibration, humidity), creating separate &lt;strong&gt;mqtt out&lt;/strong&gt; nodes with unique topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pressure&lt;/strong&gt;: &lt;code&gt;plant2/Area4/Cell2/DeviceA/pressure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vibration&lt;/strong&gt;: &lt;code&gt;plant2/Area4/Cell2/DeviceA/vibration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Humidity&lt;/strong&gt;: &lt;code&gt;plant2/Area4/Cell2/DeviceA/humidity&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each mqtt out node should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the same broker configuration (click the pencil icon next to Server and select your existing broker)&lt;/li&gt;
&lt;li&gt;Have its own unique topic&lt;/li&gt;
&lt;li&gt;Be connected to the corresponding Change node output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Step 3.4: Deploy and Verify the Connection&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; in the top-right corner of Node-RED to activate your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the status indicator beneath each &lt;strong&gt;mqtt out&lt;/strong&gt; node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Green dot with &amp;quot;connected&amp;quot;&lt;/strong&gt;: Successfully connected and publishing data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Red dot with &amp;quot;disconnected&amp;quot;&lt;/strong&gt;: Connection failed—check your broker credentials and network connectivity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yellow dot&lt;/strong&gt;: Connecting or waiting for data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To verify data is flowing to your UNS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Broker&lt;/strong&gt; section in the FlowFuse platform&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Hierarchy&lt;/strong&gt; tab to view your topic structure&lt;/li&gt;
&lt;li&gt;You should see your topics organized by the ISA-95 hierarchy you defined&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse topic hierarchy interface showing UNS structure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-mqtt-topic-hierarchy-monitoring.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse topic hierarchy interface showing UNS structure&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once your flow is successfully publishing data, you&#39;ve established your Unified Namespace. Other systems can now subscribe to these MQTT topics to consume the data for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloud analytics platforms&lt;/strong&gt; for historical analysis and reporting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/strong&gt; for real-time monitoring and visualization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predictive maintenance systems&lt;/strong&gt; for equipment health monitoring&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Business intelligence tools&lt;/strong&gt; for operational insights&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alert and notification systems&lt;/strong&gt; for automated responses to threshold breaches&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This setup effectively bridges legacy Modbus devices with modern IoT infrastructure, enabling data-driven decision-making and unlocking the full potential of your industrial operations.&lt;/p&gt;
&lt;p&gt;For more information on using MQTT with Node-RED, please read &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;Using MQTT with Node-RED&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/</id>
        <title>Building a Unified Namespace (UNS) with FlowFuse</title>
        <summary>Implement your Unified Namespace seamlessly using our low-code platform</summary>
        <updated>2024-11-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;As systems and devices become more connected, managing data from different sources can be tricky. A &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt; solves this by centralizing all your data in one place, making it easy to access and use.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; makes building a UNS simple. It connects old and new systems, collects data from devices and applications, and streamlines workflows. With tools like Node-RED for data flow, MQTT for real-time updates, and a central management layer, FlowFuse helps you improve efficiency and make better decisions.&lt;/p&gt;
&lt;p&gt;This article will show you how to build your UNS using FlowFuse, step by step.&lt;/p&gt;
&lt;h2 id=&quot;building-a-uns-with-real-time-sensor-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#building-a-uns-with-real-time-sensor-data&quot;&gt;Building a UNS with Real-Time Sensor Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section explains how to set up a Unified Namespace (UNS) using FlowFuse, a Raspberry Pi, and an ADXL345 sensor. The Raspberry Pi collects data from the sensor, which we collect and process in Node-RED, calculate vibration magnitude, format it, and send it to the UNS using standardized topic names.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-collect-metrics-from-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#step-1%3A-collect-metrics-from-devices&quot;&gt;Step 1: Collect Metrics from Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step in building your UNS is collecting data from your devices. The method you choose will depend on the type of device and the communication protocol it supports. For example, many devices use traditional communication standards like Modbus, while others, such as industrial controllers, might rely on OPC-UA.&lt;/p&gt;
&lt;p&gt;Fortunately, Node-RED provides support for a wide range of industrial protocols, from legacy to modern ones. While older protocols like Modbus and OPC-UA were originally designed for machine-to-machine (M2M) communication and are not directly compatible with cloud systems, Node-RED acts as a bridge to overcome this limitation.&lt;/p&gt;
&lt;p&gt;By leveraging Node-RED, you can collect data from these legacy systems, process and transform the data using low-code workflows, and then seamlessly send it to the cloud via modern protocols such as MQTT, Kafka, AMQP, and more.&lt;/p&gt;
&lt;p&gt;In our example, Node-RED can directly collect metrics from sensor using &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-i2c&quot;&gt;I2C&lt;/a&gt; on the Raspberry Pi. This approach simplifies the process by eliminating the need for additional communication layers. To run Node-RED on the Raspberry Pi, we use &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt;, This agent enables you to remotely monitor, manage, and build Node-RED flows securely through the FlowFuse platform remotely. &lt;a href=&quot;https://flowfuse.com/node-red/hardware/&quot;&gt;See here&lt;/a&gt; for more details on how to set up and run FlowFuse Device Agent on different devices.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-transform-and-process-the-collected-metrics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#step-2%3A-transform-and-process-the-collected-metrics&quot;&gt;Step 2: Transform and Process the Collected metrics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you&#39;ve collected data from your devices, the next step is to transform it using Node-RED. Industrial systems often use different protocols such as Modbus and OPC UA, and each might have its own data structure, which can create challenges for integration. For example, the ADXL345 sensor which we are uisng in our practile example outputs raw data as electrical signals (buffer data). We first need to format it into a human-readable format and then calculate the Magnitude, a standard vibration monitoring unit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Data Transformation Matters:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: Ensures data from different sources follows the same structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: It makes integrating data from various systems easier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speed&lt;/strong&gt;: Simplifies data access for faster insights and decision-making.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;example%3A-transforming-data-from-adxl345-sensor-(raspberry-pi)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#example%3A-transforming-data-from-adxl345-sensor-(raspberry-pi)&quot;&gt;Example: Transforming Data from ADXL345 Sensor (Raspberry Pi)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Raw data from the ADXL345 sensor might look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-62&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-62&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;244&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-62&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Using a &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/function/&quot;&gt;Function node&lt;/a&gt; in Node-RED, we can convert this into a human-readable format.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Function node: Transforming Raw Data into Readable Format&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/function-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Function node: Transforming Raw Data into Readable Format&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After transformation, the data will look as shown below.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-72&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-72&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.09765625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;-0.046875&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;-0.8828125&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-72&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;While this is more readable, it can still be challenging to monitor changes in vibration quickly or detect anomalies. To simplify monitoring, we can calculate the Magnitude, a single metric commonly used in vibration monitoring.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change node: Calculating Magnitude&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-calculating-magnitude.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change node: Calculating Magnitude&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After calculating the Magnitude using a &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/change/&quot;&gt;Change node&lt;/a&gt;, the data might look like this:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-82&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-82&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.00390625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;-0.07421875&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;-0.8515625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;magnitude&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.8547996098775871&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-82&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Now, the data is easier to monitor with a single metric (Magnitude), but this structure is still not optimal for a UNS. We need to transform it further to provide more context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Data Structure for UNS:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To make the data more useful for integration and interpretation in a UNS, we can transform it to include additional context, such as units and timestamps, while removing unnecessary metrics like the three-axis components (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;z&lt;/code&gt;). The easiest and most low-code approach for achieving this in Node-RED is to use the Change node, which is specifically designed for formatting and structuring payloads.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Change Node: Formatting and structuring payload for UNS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-structering-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Change Node: Formatting and structuring payload for UNS&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After formatting, the data will look as shown below:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-98&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-98&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vibration&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-11-13T10:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;m/s²&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.8547996098775871&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-98&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This format is more structured and consistent, with important labels like &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;unit&lt;/code&gt;, and &lt;code&gt;timestamp&lt;/code&gt; that provide meaningful context. It clarifies that the value represents the Magnitude of vibration in &lt;strong&gt;m/s²&lt;/strong&gt; and provides the precise time when the data was collected.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-setting-up-your-uns-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#step-3%3A-setting-up-your-uns-broker&quot;&gt;Step 3: Setting Up Your UNS Broker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, it&#39;s time to configure your UNS broker. As mentioned, we’ll use the &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;FlowFuse MQTT Broker&lt;/a&gt;. This broker is integrated within the FlowFuse platform to simplify your workflow by eliminating the need for multiple separate services. With FlowFuse, you can monitor and configure everything from a single, centralized platform. This ensures you can efficiently monitor, manage, and configure your UNS without juggling multiple tools or services.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps to Set Up the FlowFuse MQTT Broker:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to the FlowFuse platform and navigate to &lt;strong&gt;&amp;quot;Broker&amp;quot;&lt;/strong&gt; in the left sidebar.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;&amp;quot;Create Client&amp;quot;&lt;/strong&gt; button at the top-right corner to add a new MQTT client.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configure the client&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Provide a &lt;strong&gt;Username&lt;/strong&gt; and &lt;strong&gt;Password&lt;/strong&gt; for secure access.&lt;/li&gt;
&lt;li&gt;Define an &lt;strong&gt;Access Pattern&lt;/strong&gt; to manage client permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;&amp;quot;Create&amp;quot;&lt;/strong&gt; to generate the client.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Note: Enterprise-level teams can register up to 20 clients, and teams-level teams can register up to 5 clients as part of their plan. The ability to purchase additional packs of clients will come in a near future release.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Copy the client ID you generated from the list and save it somewhere for later use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Interface for creating MQTT Client&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/creating-client-interface.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Interface for creating MQTT Client&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-choosing-your-topic-naming-convention&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#step-4%3A-choosing-your-topic-naming-convention&quot;&gt;Step 4: Choosing Your Topic Naming Convention&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The key to building a successful UNS is organizing your data with a clear and consistent naming convention. A well-designed convention ensures data is accessible and understandable across systems and users, simplifying communication and integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ISA-95&lt;/strong&gt; is a standard for industrial systems encompassing various manufacturing and communication aspects. However, when it comes to communication, ISA-95 often relies on point-to-point (P2P) connections between systems and devices. These connections can introduce complexity, delays, and other challenges.&lt;/p&gt;
&lt;p&gt;While we are building a UNS to address the problems and limitations we observed with point-to-point communication, we can still leverage key elements of ISA-95 that remain valuable for improving production efficiency. One of the central aspects of ISA-95 is its equipment hierarchical model, which links various layers of a factory, from physical devices to enterprise systems. By adapting this model to your data architecture, you can simplify data access and management across the entire system.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;ISA-95 : Equipment Hierarchical Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/isa-95-equipement-model.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;ISA-95 : Equipment Hierarchical Model&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For example, following an ISA-95-based equipment hierarchy to define your topic naming convention allows you to access data from devices, sensors, or any other source without knowing their specific addresses or tags—such as for a PLC. With clarity and ease, this logical structure enables you to retrieve relevant information from different system layers (e.g., from control systems to MES or ERP).&lt;/p&gt;
&lt;p&gt;Example topic structure based on ISA-95 equipment model hierarchy:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Plant1/Area3/Line4/Cell2/DeviceA&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Plant1/Area4/Line5/Cell6/DeviceB&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can also use the &lt;a href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/&quot;&gt;&lt;strong&gt;Sparkplug B&lt;/strong&gt;&lt;/a&gt; naming convention for MQTT topics, which offers a structured hierarchy and standard. However, the Sparkplug B convention has some limitations in terms of flexibility. A typical &lt;strong&gt;Sparkplug B topic&lt;/strong&gt; follows this structure:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;spBv1.0/{groupID}/{edgeNodeID}/{deviceID}/{messageType}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;While Sparkplug B provides a standardized topic model, its hierarchy may not always suit the specific needs of your architecture. Alternative methods, such as the Paris and Schultz models, help address these limitations with Sparkplug B topics. However, to keep things simple and avoid unnecessary complexity, we will use plain MQTT with the ISA-95 hierarchy.&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-sending-collected-metrics-to-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#step-5%3A-sending-collected-metrics-to-uns&quot;&gt;Step 5: Sending Collected metrics to UNS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With your topic naming convention chosen, it’s time to send the data to the UNS. In Node-RED, we will use the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/mqtt-in/&quot;&gt;MQTT Out&lt;/a&gt; node to send the transformed data to the broker.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an MQTT out node into your flow.&lt;/li&gt;
&lt;li&gt;Configure the node to connect to the FlowFuse MQTT Broker using the client credentials generated earlier.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Use environment variables to secure configuration and prevent exposing credentials when sharing flows. This ensures that sensitive data remains secure and allows easy sharing without compromising security. For more details, refer to the &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Article: Using Environment Variables in Node-RED&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring mqtt-broker-config node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring mqtt-broker-config node&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;![Configuring mqtt-broker-config node](./images/mqtt-broker-config-security
.png){data-zoomable}
&lt;em&gt;Configuring mqtt-broker-config node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Set the &lt;strong&gt;topic&lt;/strong&gt; using your predefined naming convention (e.g., &lt;code&gt;Plant1/Area3/Line4/Cell2/RPI1&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring mqtt-out node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-out-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring mqtt-out node&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Connect the input of the mqtt out node to your data transformation flow and deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For information on how to use MQTT with Node-RED, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;Using MQTT with Node-RED&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After deploying, you can monitor the topic hierarchy on the FlowFuse platform by switching to the &amp;quot;Hierarchy&amp;quot; tab in the Broker interface.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Monitoring your mqtt topic hierarchy within FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/topic-hierarchy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Monitoring your mqtt topic hierarchy within FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once your data is in the UNS, you have a centralized, real-time view of your operations. This unified structure enables easier access, sharing, and analysis of data across systems, helping you drive better decisions, improve efficiency, and gain valuable insights to optimize your processes.&lt;/p&gt;
&lt;p&gt;With real-time data access, you can create monitoring dashboards using the &lt;a href=&quot;https://flowfuse.com/platform/dashboard/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; with a low-code approach, integrate with other cloud solutions, or leverage it further for enhanced analytics or automation.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Dashboard Monitoring Vibrations&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Dashboard Monitoring Vibrations&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse makes building a Unified Namespace (UNS) easy by centralizing data from systems, devices, and sensors. With seamless integration of Node-RED, MQTT, and its enterprise layer, FlowFuse ensures smooth data flow, real-time insights, and efficient management. It simplifies operations, enhances productivity, and improves system interoperability, making it easy to adapt your UNS to specific needs and support real-time analytics and automation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/</id>
        <title>The Death of Point-to-Point: Why You Need a Unified Namespace</title>
        <summary>Traditional Point-to-Point Connection Model is Holding Back Manufacturing Innovation - Unified Namespace (UNS) Can Transform Factory Operations</summary>
        <updated>2024-11-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Manufacturing has changed significantly over the years, driven by new technology and the need for better communication between systems. In the past, point-to-point (P2P) connections, where devices communicate directly with each other, were the standard. However, as factories become more complex, P2P connections are no longer practical. This article explains why P2P connections are outdated and how a Unified Namespace (UNS) offers a better, more flexible solution.&lt;/p&gt;
&lt;h2 id=&quot;what-are-point-to-point-connections%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#what-are-point-to-point-connections%3F&quot;&gt;What are Point-to-Point Connections?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Point-to-point connection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/p2p.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Point-to-point connection&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Point-to-point (P2P) connections are direct links between two systems or devices, allowing them to communicate with each other. They can be physical, like cables, or network-based (client-server), like a machine sending data to a server.&lt;/p&gt;
&lt;p&gt;In a P2P setup, each connection links exactly two systems. These systems could be hardware, software, or even databases, exchanging data tailored to their needs.&lt;/p&gt;
&lt;p&gt;For example, a machine might send performance data directly to a control system, or a sensor could send real-time measurements to a monitoring device. It’s a straightforward way to get systems talking, but as the number of devices grows, it becomes increasingly complex to manage.&lt;/p&gt;
&lt;h2 id=&quot;why-point-to-point-connections-no-longer-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#why-point-to-point-connections-no-longer-work&quot;&gt;Why Point-to-Point Connections No Longer Work&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As manufacturing moves toward more modern, interconnected approaches like Industry 4.0, the limitations of point-to-point connections become more apparent. Here&#39;s why P2P connections are no longer sufficient for today’s manufacturing environments:&lt;/p&gt;
&lt;h3 id=&quot;1.-limited-data-sharing%2C-visibility%2C-and-delayed-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#1.-limited-data-sharing%2C-visibility%2C-and-delayed-data&quot;&gt;1. Limited Data Sharing, Visibility, and Delayed Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Point-to-point connections often lead to data silos, where devices or machines communicate only with their immediate hierarchy level. This isolation severely limits system-wide visibility, making it challenging to share critical data in real-time. Consequently, problems such as defective products, unexpected downtime, and the need for rework may go unnoticed until the damage is done.&lt;/p&gt;
&lt;p&gt;In modern manufacturing, real-time data is indispensable for maintaining operational efficiency. However, point-to-point connections introduce significant delays, as data must traverse multiple layers—control systems (Level 1), supervisory control (Level 2), manufacturing execution systems (Level 3), and finally, higher-level management systems (Level 4) as outlined in the ISA-95 model. Each additional layer compounds latency, slowing response times and postponing the detection of issues, see also our post on &lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/&quot;&gt;Why the Automation Pyramid slows you down&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Without integrated, real-time data across teams, such as quality control, problems like defective parts may not be addressed promptly, leading to increased waste and customer dissatisfaction. The lack of seamless data sharing results in visibility gaps that impede decision-making, reducing the ability to act swiftly. In fast-paced environments, these delays not only hinder operational efficiency but also have a direct negative impact on profitability.&lt;/p&gt;
&lt;h3 id=&quot;2.-inflexibility%2C-limiting-innovation%2C-and-causing-downtime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#2.-inflexibility%2C-limiting-innovation%2C-and-causing-downtime&quot;&gt;2. Inflexibility, Limiting Innovation, and Causing Downtime&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Point-to-point connections create a rigid and inflexible network. When new technology or equipment is added, the entire system often requires reconfiguration, leading to significant downtime. For instance, if a new machine is introduced to the production line, many connections may need to be adjusted or re-established, which can temporarily halt production.&lt;/p&gt;
&lt;p&gt;This downtime disrupts the flow of operations and makes it harder to implement new technologies quickly, slowing down innovation. As a result, manufacturers may struggle to stay competitive, as they can&#39;t integrate advancements like automation, real-time analytics, or AI without significant delays and costly interruptions.&lt;/p&gt;
&lt;h3 id=&quot;3.-high-costs-over-time-and-maintenance-complexity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#3.-high-costs-over-time-and-maintenance-complexity&quot;&gt;3. High Costs Over Time and Maintenance Complexity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At first glance, point-to-point (P2P) connections may appear to be a cost-effective and straightforward solution. However, as systems expand, the true costs and complexities become increasingly apparent. In the automation pyramid (ISA-95 model), communication occurs across multiple hierarchical levels, with field devices interacting with controllers, controllers with SCADA, and SCADA with higher-level systems such as MES and ERP.&lt;/p&gt;
&lt;p&gt;While this layered structure can keep connections orderly, it quickly becomes a logistical nightmare when scaling. Introducing new devices often triggers a cascade of necessary updates and reconfigurations across various levels. For example, adding a new field device typically requires adjustments to the controller, followed by updates to the SCADA system, creating a ripple effect that impacts the entire system.&lt;/p&gt;
&lt;p&gt;This ongoing need for constant reconfiguration not only drives up costs but also introduces significant complexity in maintenance. As the system grows, so does the effort and resources required to manage it, making the P2P model inefficient and prohibitively expensive in environments that demand agility, scalability, and long-term sustainability. Ultimately, the simplicity of P2P connections gives way to an increasingly cumbersome and expensive maintenance burden, undermining its initial advantages.&lt;/p&gt;
&lt;h3 id=&quot;4.-security-vulnerabilities&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#4.-security-vulnerabilities&quot;&gt;4. Security Vulnerabilities&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As the number of point-to-point connections increases, so does the risk of security breaches. Each connection represents a potential vulnerability, and if one connection in the network is compromised, the entire system becomes a target for attackers.&lt;/p&gt;
&lt;p&gt;In large manufacturing environments, securing every individual connection becomes daunting. Any new device or system can introduce additional vulnerabilities, creating more opportunities for attackers to exploit. A compromised point-to-point connection could lead to production halts, loss of sensitive data, or even physical damage to machinery.&lt;/p&gt;
&lt;p&gt;For example, imagine a situation where a hacker gains access to a machine’s control system through a compromised point-to-point connection. The attacker could intentionally cause a malfunction, halt production, or extract confidential information. The complexity of managing security for each connection makes it difficult to maintain a secure, reliable network.&lt;/p&gt;
&lt;h3 id=&quot;5.-scalability-issues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#5.-scalability-issues&quot;&gt;5. Scalability Issues&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most significant drawbacks of P2P connections in manufacturing is their inability to scale efficiently. As production lines grow, so too do the number of devices, systems, and connections that must be managed. With a P2P architecture, each new device or system typically requires a direct, dedicated connection to each relevant part of the network. This creates a spaghetti network of interwoven links that becomes increasingly unwieldy and difficult to manage as the system expands.&lt;/p&gt;
&lt;p&gt;In a traditional P2P setup, scaling the network means manually creating additional links, configuring them, and ensuring that the new connections fit seamlessly into the existing infrastructure. This process is time-consuming, error-prone, and highly resource-intensive, leading to increased complexity and longer downtimes as you scale.&lt;/p&gt;
&lt;p&gt;When scaling a P2P network, changes made to one part of the system often trigger a ripple effect throughout the entire network. For instance, adding a new sensor may require updating the controller, the SCADA system, and even the Manufacturing Execution System (MES). This cascading need for updates across different layers of the network makes scaling more complicated and costly. Furthermore, the introduction of new devices means additional configuration and troubleshooting, often leading to disruptions in operations and extended downtimes while the new devices are integrated.&lt;/p&gt;
&lt;p&gt;These issues compound when scaling across multiple production lines or sites, creating an increasingly complex web of p2p connections. As the number of devices grows, so does the risk of errors, network failures, and delays. This makes it difficult for manufacturers to respond to the growing demands of production while maintaining efficiency, reliability, and uptime.&lt;/p&gt;
&lt;h2 id=&quot;unified-namespace%3A-the-modern-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#unified-namespace%3A-the-modern-solution&quot;&gt;Unified Namespace: The Modern Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img width=&quot;400px&quot; data-zoomable=&quot;&quot; alt=&quot;Hub and Spoke Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/hub.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Hub and Spoke Model&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A Unified Namespace (UNS) is a more straightforward way to connect devices and systems in a factory. Instead of having separate connections between each device, everything is connected through one central hub, which we call the &lt;strong&gt;hub-and-spoke&lt;/strong&gt; model. This means devices don’t need to be directly linked to each other, making the system easier to manage and maintain; for more information on Unified Namespace, read our article: &lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Introduction to unified namespace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With a UNS, adding new devices or systems becomes straightforward. Rather than setting up multiple direct connections—like in a point-to-point system—new devices (spokes) connect to the central hub. This reduces the complexity of growing your system and eliminates downtime. If equipment is replaced or updated, only that device needs to be reconnected to the hub rather than reconfiguring the entire network.&lt;/p&gt;
&lt;p&gt;A UNS also improves data sharing. All data is collected in one place, so any system that needs it can access it in real time. This leads to quicker decisions and faster responses to problems. With fewer connections to manage, the costs of maintaining the system are lower. Plus, the central hub makes the whole system more secure, as fewer direct connections need to be protected.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Publish-Subscribe Archtecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pub-sub.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Publish-Subscribe Archtecture&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We use a &lt;strong&gt;publish-subscribe (pub/sub)&lt;/strong&gt; architecture to implement a hub-and-spoke model in a UNS. In this architecture, devices, systems send data to a central broker, and other devices can subscribe to the data they need. This approach eliminates the need for a complex network of point-to-point connections, making it easier to scale, update, and maintain the system.&lt;/p&gt;
&lt;p&gt;This model addresses all the significant problems of point-to-point connections. For more information on how pub/sub solves these problems or why UNS needs pub/sub, read the article: &lt;a href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/&quot;&gt;Why UNS Needs Pub/Sub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; is a widely used for implementing the publish-subscribe model. It is lightweight, efficient, and works well in manufacturing environments where network reliability can be inconsistent.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Unified Namespace&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr-in-uns.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Unified Namespace&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To simplify the creation of a UNS in your manufacturing environment, &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; provides an integrated MQTT broker service. The platform makes building, scaling, and managing Node-RED solutions easy. It supports seamless connections between devices, services, and APIs using over 5,000 community-contributed nodes for data collection. FlowFuse also enables efficient data transformation and visualization with a low-code approach, remote management of edge devices, and team collaboration on projects. With everything centralized on one platform, FlowFuse offers high security, scalability, and availability to optimize and maintain your system effectively.&lt;/p&gt;
&lt;p&gt;Get started with this article &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Building UNS with FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Due to complexity, high maintenance costs, and security risks, point-to-point (P2P) connections are becoming less effective in modern factories. A Unified Namespace (UNS) solves these problems by connecting devices through a central hub, making managing, scaling, and securing systems easier. UNS improves data sharing and reduces downtime. Tools like FlowFuse make it simple to set up and manage a UNS, offering a more efficient and flexible solution for manufacturing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/introducing-industrial-visionaries-podcast/</id>
        <title>Introducing the Industrial Visionaries Podcast!</title>
        <summary>Introducing Industrial Visionaries, the podcast that explores the minds behind the industry&#39;s biggest breakthroughs.</summary>
        <updated>2024-11-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/introducing-industrial-visionaries-podcast/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Today, we’re excited to announce our new podcast: Industrial Visionaries!&lt;/p&gt;
&lt;p&gt;This show is dedicated to exploring the transformative power of technology in the manufacturing sector.&lt;/p&gt;
&lt;p&gt;In each episode, our host ZJ van de Weg, CEO of FlowFuse, brings you face-to-face with industry leaders who are pioneering digital solutions, sharing insights that will help you navigate the future of manufacturing.&lt;/p&gt;
&lt;h3 id=&quot;episode-1%3A-flowfuse%E2%80%99s-nick-o%E2%80%99leary-on-low-code-development-and-its-impact-on-iot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/introducing-industrial-visionaries-podcast/#episode-1%3A-flowfuse%E2%80%99s-nick-o%E2%80%99leary-on-low-code-development-and-its-impact-on-iot&quot;&gt;Episode 1: FlowFuse’s Nick O’Leary on Low-Code Development and Its Impact on IoT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our inaugural episode of Industrial Visionaries, our host ZJ van de Weg, chats with fellow FlowFuse exec, Nick O’Leary, CTO &amp;amp; Founder. Nick, who is also the creator of Node-RED, shares his extensive insights into the evolution of the Internet of Things (IoT). He discusses the early days of IoT and the transformative role of edge computing, highlighting how increased computing power has shifted data processing closer to devices.&lt;/p&gt;
&lt;p&gt;Listen to the first episode on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/us/podcast/ep-1-flowfuses-nick-oleary-on-low-code-development/id1781774461?i=1000678217258&quot;&gt;Apple Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open.spotify.com/episode/6HJB35FbK1U7pVNpTyM6P2&quot;&gt;Spotify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=AI-bjry8vLU&quot;&gt;YouTube&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We look forward to bringing you more conversations with actionable insights that help in your pursuit to innovate in your industry.&lt;/p&gt;
&lt;p&gt;For the latest episodes, search for “Industrial Visionaries” on Spotify, Apple, YouTube, or wherever you listen to podcasts!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/</id>
        <title>Getting the Most Out of MQTT for Industrial IoT</title>
        <summary>Best Practices for Optimizing MQTT in Industrial IoT Systems</summary>
        <updated>2024-11-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;MQTT is a go-to protocol for industrial IoT, known for its efficiency, scalability, and ease of use. While it offers great flexibility in handling real-time data, there are key factors to consider in order to get the most out of it. From ensuring data consistency to addressing security and performance concerns, these factors can significantly enhance MQTT’s effectiveness in industrial settings.&lt;/p&gt;
&lt;p&gt;This post dives into how to optimize MQTT for industrial IoT, covering best practices and key considerations. It also highlights how FlowFuse can help streamline MQTT communication, improving data reliability, security, and integration across devices and systems.&lt;/p&gt;
&lt;h2 id=&quot;standardizing-data-formats-for-better-quality-and-consistency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#standardizing-data-formats-for-better-quality-and-consistency&quot;&gt;Standardizing Data Formats for Better Quality and Consistency&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Industrial data is generated by a wide variety of devices, machines, and systems, making it highly valuable. However, to fully leverage this data, it needs to be standardized and formatted in a way that ensures seamless processing across different systems, especially since it can come in a variety of formats.&lt;/p&gt;
&lt;p&gt;One of MQTT’s key strengths is its flexibility in handling various data formats. While this is an advantage, it can sometimes require additional effort to ensure that the data is structured consistently and in a way that’s easy to use. Standardizing data formats helps organizations streamline processes, making data easier to interpret, analyze, and act upon. Without a consistent approach, data inconsistencies may arise, slowing down insights or causing compatibility issues.&lt;/p&gt;
&lt;p&gt;Frameworks like &lt;a href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/&quot;&gt;Sparkplug B&lt;/a&gt; are designed to help address this by providing a standardized way to handle MQTT payloads. By adopting such frameworks, companies can ensure that data is delivered in a consistent, well-structured format, improving compatibility and making it easier to analyze. This not only simplifies integration across diverse systems but also enables more reliable decision-making and efficient operations.&lt;/p&gt;
&lt;h2 id=&quot;optimizing-payloads-and-bandwidth-for-efficient-mqtt-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#optimizing-payloads-and-bandwidth-for-efficient-mqtt-communication&quot;&gt;Optimizing Payloads and Bandwidth for Efficient MQTT Communication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT is designed for lightweight, efficient messaging, which makes it ideal for many IIoT applications. However, in cases where large amounts of data or high-frequency messages need to be transmitted, bandwidth constraints can sometimes impact performance.&lt;/p&gt;
&lt;p&gt;While the MQTT protocol supports large message payloads (up to 250 MB), transmitting large files such as high-resolution images or detailed sensor data can slow down communication. Fortunately, there are simple yet effective strategies to keep your MQTT network running smoothly, even when dealing with sizable payloads.&lt;/p&gt;
&lt;p&gt;To optimize performance, consider compressing your data before sending it, which reduces the overall size of the payload and makes transmission faster and more efficient. For even larger files, such as video or binary data, a great approach is to store these files externally (e.g., in cloud storage like AWS S3) and send only a reference or pointer to the data. This avoids the need to transmit large files over MQTT while ensuring data accessibility.&lt;/p&gt;
&lt;p&gt;By using these strategies, you can optimize MQTT performance and ensure that your system runs efficiently, even when handling large or high-frequency data. These techniques allow MQTT to continue providing fast, reliable, and scalable communication, regardless of the data size or frequency.&lt;/p&gt;
&lt;h2 id=&quot;ensuring-reliable-data-delivery-with-mqtt%E2%80%99s-qos-levels&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#ensuring-reliable-data-delivery-with-mqtt%E2%80%99s-qos-levels&quot;&gt;Ensuring Reliable Data Delivery with MQTT’s QoS Levels&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In industrial environments, the accuracy and timeliness of data transmission are crucial for maintaining operational efficiency and safety. MQTT’s publish-subscribe model is designed for lightweight, real-time messaging, but it’s important to understand how to leverage its features to ensure the reliability and integrity of the data flow.&lt;/p&gt;
&lt;p&gt;While the protocol is generally robust, in some cases, challenges such as network disruptions or temporary communication failures can occur. These can lead to issues such as message loss or delivery out of order. Fortunately, MQTT provides built-in mechanisms to address these challenges and ensure that messages reach their intended destination reliably.&lt;/p&gt;
&lt;p&gt;One of the key feature for managing message delivery is Quality of Service (QoS), which defines how MQTT handles message delivery:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QoS 0&lt;/strong&gt;: Messages are delivered at most once, with no guarantee of delivery or order. This level is ideal for scenarios where occasional message loss is acceptable and minimizing network overhead is critical.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QoS 1&lt;/strong&gt;: Guarantees that messages are delivered at least once, although duplicates may occur. This is useful when data consistency is important, but some duplication can be handled by the system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QoS 2&lt;/strong&gt;: Ensures messages are delivered exactly once and in the correct order. This highest level of QoS is suitable for scenarios where data integrity and sequencing are paramount, such as in robotic control systems or safety-critical operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By choosing the right QoS level, you can align MQTT’s behavior with the operational needs of your system, balancing between performance, data reliability, and system resources. For real-time applications, a lower QoS level may be sufficient, while in more critical situations, the higher QoS levels offer a stronger guarantee of data delivery and integrity.&lt;/p&gt;
&lt;p&gt;With these options, MQTT allows you to fine-tune message delivery to meet the specific requirements of your industrial IoT environment, ensuring that data flows smoothly and reliably, even in challenging network conditions.&lt;/p&gt;
&lt;h2 id=&quot;implementing-acknowledgment-mechanisms-in-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#implementing-acknowledgment-mechanisms-in-mqtt&quot;&gt;Implementing Acknowledgment Mechanisms in MQTT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One important consideration when working with MQTT is the lack of built-in acknowledgment mechanisms. Unlike traditional request-response communication models, where the receiver explicitly confirms the receipt of a message, MQTT doesn&#39;t natively offer a direct way for the receiver to acknowledge successful message receipt.&lt;/p&gt;
&lt;p&gt;This lack of visibility can pose challenges in scenarios where it’s crucial to ensure that data has been transmitted successfully and processed as expected. In some industrial systems, failure to confirm receipt of messages could lead to operational uncertainty or potential errors.&lt;/p&gt;
&lt;p&gt;However, while MQTT does not provide this feature out-of-the-box, it is possible to implement acknowledgment mechanisms to enhance reliability. we can use a separate topic where the receiver sends a confirmation message (such as “ack” or “received”) back to the sender, indicating that the message was successfully processed.&lt;/p&gt;
&lt;p&gt;This allow you to implement acknowledgment functionality, but they do require additional planning and development effort. Ensuring that these mechanisms are correctly designed and integrated can improve system reliability by providing the necessary feedback loop for confirming message receipt and processing.&lt;/p&gt;
&lt;p&gt;By incorporating acknowledgment systems, you can enhance the visibility and confidence in data transmission, ensuring that your industrial IoT system operates smoothly and that no critical messages are missed or lost.&lt;/p&gt;
&lt;h2 id=&quot;optimizing-mqtt-for-resource-constrained-environments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#optimizing-mqtt-for-resource-constrained-environments&quot;&gt;Optimizing MQTT for Resource-Constrained Environments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While MQTT’s use of TCP/IP ensures reliable message delivery, it can introduce challenges in environments where devices have limited resources. Maintaining persistent TCP connections can consume significant processing power and memory, which may be a concern for low-power or resource-constrained devices.&lt;/p&gt;
&lt;p&gt;To address this, some IoT systems use MQTT-SN (MQTT for Sensor Networks), a variant that operates over UDP and is specifically designed for devices with limited resources. MQTT-SN reduces the overhead associated with maintaining a TCP connection, making it a better fit for battery-powered or embedded devices that need to conserve energy. However, it&#39;s important to note that MQTT-SN is distinct from the standard MQTT specification, as it involves different message formats and communication mechanisms.&lt;/p&gt;
&lt;p&gt;By carefully selecting the appropriate protocol and architecture for your specific use case, you can continue to leverage MQTT-like messaging capabilities, while optimizing performance in environments with limited resources.&lt;/p&gt;
&lt;h2 id=&quot;ensuring-security-in-mqtt-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#ensuring-security-in-mqtt-deployments&quot;&gt;Ensuring Security in MQTT Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Security is essential when using MQTT in industrial environments. While MQTT offers powerful features like encryption and authentication, it&#39;s crucial to configure these elements correctly to maximize security. A properly secured MQTT deployment ensures that your system remains protected from risks such as data interception, unauthorized access, or man-in-the-middle attacks, while ensuring that your communication remains secure and reliable.&lt;/p&gt;
&lt;p&gt;To begin, implementing encryption (SSL/TLS) is an important step to protect the data transmitted between devices and brokers. This ensures that sensitive information is kept confidential and is shielded from unauthorized access. By enabling encryption, you create a secure communication pathway that prevents eavesdropping and data tampering.&lt;/p&gt;
&lt;p&gt;Next, consider authentication for all devices and users. By using mechanisms such as usernames, passwords, or client certificates, you can ensure that only authorized devices and users can connect to your MQTT broker. This access control mechanism ensures that only the right people and devices have access to the network, safeguarding it from potential threats.&lt;/p&gt;
&lt;p&gt;Topic-level access control is another key aspect of securing your MQTT deployment. By managing who can publish or subscribe to specific topics, you can prevent unauthorized access to sensitive data or critical commands. For example, you can restrict which devices or users are allowed to subscribe to specific topics that control industrial equipment or monitor sensitive processes. This level of control ensures that only trusted entities can interact with certain parts of your system, reducing the risk of malicious actions.&lt;/p&gt;
&lt;p&gt;In addition to restricting access to topics, it&#39;s also important to regularly monitor your MQTT traffic for any unusual activity or anomalies. By staying vigilant and analyzing traffic patterns, you can identify potential security threats early and take action to prevent any disruptions.&lt;/p&gt;
&lt;p&gt;By configuring your MQTT setup with encryption, authentication, topic-level access control, and ongoing monitoring, you can create a secure, reliable, and scalable IoT system. A well-secured MQTT deployment not only reduces risks but also enhances the efficiency and safety of industrial operations, providing peace of mind as your system grows.&lt;/p&gt;
&lt;h2 id=&quot;minimizing-risks-of-single-point-of-failure-and-vendor-lock-in&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#minimizing-risks-of-single-point-of-failure-and-vendor-lock-in&quot;&gt;Minimizing Risks of Single Point of Failure and Vendor Lock-In&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When using MQTT for industrial operations, it’s important to address the potential risks associated with a single point of failure—specifically the central broker. While the broker is crucial for managing message delivery, its failure could disrupt the entire data flow, impacting operations. However, this challenge can be effectively managed with strategies like high availability, load balancing, and robust backup solutions. By implementing these best practices, you ensure that your system remains reliable and resilient, even in the event of a failure.&lt;/p&gt;
&lt;p&gt;Another consideration is vendor lock-in, which can occur when businesses become reliant on a specific MQTT broker or service. While this may seem convenient at first, it can make future changes or migrations difficult due to proprietary features or configurations that aren&#39;t easily compatible with other systems. This is a scenario that can be easily avoided with careful planning.&lt;/p&gt;
&lt;p&gt;Although MQTT is an open standard, some cloud services may not fully adhere to the MQTT 3.1.1 specification. This can sometimes lead companies to rely on proprietary software development kits (SDKs) for sending MQTT messages. While these tools can work well initially, they can limit your ability to switch vendors or integrate with other systems down the road.&lt;/p&gt;
&lt;p&gt;To maintain flexibility and avoid vendor lock-in, it&#39;s crucial to choose an MQTT broker that fully supports MQTT&#39;s open standards. Brokers that follow standards like MQTT 3.1.1 or MQTT 5.0 ensure compatibility and interoperability, making it easier to switch providers or integrate new technologies as your needs evolve.&lt;/p&gt;
&lt;h2 id=&quot;how-flowfuse-enhances-your-industrial-iot-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#how-flowfuse-enhances-your-industrial-iot-system&quot;&gt;How FlowFuse Enhances Your Industrial IoT System&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is an industrial data platform that streamlines the management, scaling, and security of IoT applications. Built on Node-RED at its core, FlowFuse offers seamless integration with various industrial protocols, including MQTT, ensuring reliable communication between devices. With its robust feature set, FlowFuse makes it easier to build secure, scalable, and efficient IoT solutions for industrial environments&lt;/p&gt;
&lt;p&gt;A key strength of FlowFuse is its ability to standardize data before sending it to the MQTT broker. Using Node-RED’s intuitive low-code programming capabilities, you can define consistent data formats and topics across all connected devices. This ensures smooth integration between diverse systems and maintains data consistency, allowing everything to work together seamlessly. FlowFuse also supports frameworks like &lt;a href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/&quot;&gt;Sparkplug B&lt;/a&gt;, providing additional structure for more reliable communication with MQTT payloads.&lt;/p&gt;
&lt;p&gt;Security is another area where FlowFuse excels. It allows you to configure MQTT nodes with SSL/TLS encryption, username/password authentication, and other security measures to ensure secure communication between devices. This protects sensitive data from unauthorized access and ensures that your system’s communications remain confidential.&lt;/p&gt;
&lt;p&gt;FlowFuse also simplifies the creation of acknowledgment mechanisms. With Node-RED, you can design custom workflows to track message receipt and processing, ensuring data integrity and improving operational transparency. This level of control guarantees that your system operates smoothly and reliably.&lt;/p&gt;
&lt;p&gt;Additionally, FlowFuse provides its own MQTT broker service that follows open standards, helping you avoid vendor lock-in and offering the flexibility to scale and adapt as your needs evolve. With built-in high availability, load balancing, and access control mechanisms, FlowFuse ensures continuous and reliable and secure data flow. And you can scale its capabilities by contacting FlowFuse support to meet the growing demands of your industrial IoT system.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/getting-the-most-out-of-mqtt-for-industrial-iot/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Getting the most out of MQTT for industrial IoT is all about smart strategies and the right tools. By focusing on data consistency, security, and performance, you can build a resilient and efficient IoT ecosystem. With FlowFuse, you get a powerful, flexible platform that not only streamlines MQTT communication but also helps you stay ahead of challenges like security risks and vendor lock-in. Whether you&#39;re optimizing payloads, enhancing security, or scaling your system, FlowFuse makes it easier to unlock the full potential of your industrial IoT operations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/</id>
        <title>FlowFuse 2.11: MQTT Topic Hierarchy, UI Revamp &amp; Improved Logging</title>
        <summary>Let&#39;s take a look at the new features and improvements in FlowFuse 2.11</summary>
        <updated>2024-11-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The focus of the FlowFuse 2.11 release has all been about providing clarity for our users and reducing friction in our user experience.&lt;/p&gt;
&lt;p&gt;Navigation in FlowFuse has been streamlined with a new sidebar and team-wide search feature. We&#39;ve provided an interactive visualization for your MQTT topic hierarchy, ensuring you have a clear view of your own MQTT/UNS architecture, and, we&#39;ve re-architected the audit logging to ensure you have an easy-to-understand and searchable view of everything going on in your FlowFuse Team and it&#39;s respective Applications, Instances and Devices.&lt;/p&gt;
&lt;h2 id=&quot;navigation-revamp&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#navigation-revamp&quot;&gt;Navigation Revamp&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using FlowFuse Cloud, you&#39;ll have already noticed a big improvement to our navigation sidebar on the left of the user interface that was released a couple of weeks ago. This is now packaged up into FlowFuse 2.11 and available to our self-hosted customers too.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the new navigation sidebar in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the improve left-side navigation in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the first stage of a navigation revamp we&#39;re working on, that will represent a big improvement for navigation around FlowFuse, and help make managing your applications easier.&lt;/p&gt;
&lt;p&gt;You&#39;ll notice we&#39;ve renamed &amp;quot;Devices&amp;quot; to &amp;quot;Edge Devices&amp;quot; to make it clearer that these are &lt;em&gt;instances of Node-RED&lt;/em&gt; that are running on devices, rather than just a record of the device itself. We&#39;ve also separated out many of the pages into sections, making it easier to find what you&#39;re looking for, and giving us scope to add in more in the coming weeks, which will make it easy to jump straight to the features you need.&lt;/p&gt;
&lt;h3 id=&quot;team-wide-search&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#team-wide-search&quot;&gt;Team-wide Search&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A very popular feature in the &amp;quot;home&amp;quot; view of FlowFuse is the search bar that helps you find the relevant Application, Instance, or Device you&#39;re looking for. This has been moved into the top header and will be available on every page of FlowFuse, making it even easier to find what you&#39;re looking for, wherever you are.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the team-wide search&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-search.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the team-wide search&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This will soon be followed by an update to our &amp;quot;Applications&amp;quot; view which is currently quite over-crowded. We&#39;re always looking to reduce friction for our users, and this is a big step in doing that.&lt;/p&gt;
&lt;h2 id=&quot;mqtt-topic-hierarchy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#mqtt-topic-hierarchy&quot;&gt;MQTT Topic Hierarchy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We recently &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;announced our very own MQTT Service&lt;/a&gt;, and we&#39;re following that up with an update that lets you see what topics are being used by your MQTT clients in the UI:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the UI to explore your MQTT topic hierarchy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-mqtt-hierarchy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the UI to explore your MQTT topic hierarchy&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This will make managing your event-driven applications even easier, giving you clarity on the structure of your topic-space, whether you&#39;re using the MQTT Broker for a unified namespace (UNS) or any other use case.&lt;/p&gt;
&lt;h2 id=&quot;audit-logging-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#audit-logging-improvements&quot;&gt;Audit Logging Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve improved the Audit Log views at the Team and Application levels to given you better visibility on the actions taken by users across your whole team in FlowFuse.&lt;/p&gt;
&lt;p&gt;Previously, only events associated to that &amp;quot;level&amp;quot; (e.g. Team, Application, Instance) were shown in the respective log. However, now, when you view the &amp;quot;Team&amp;quot; Audit Log, it shows not just events on that team specifically, e.g. a settings change, but also all Audit events for it&#39;s &amp;quot;children&amp;quot;, i.e. the Applications, Instances, Pipelines, etc. that are part of that team too.&lt;/p&gt;
&lt;p&gt;New filters on the right-side also make it easy to explore everything taking place in your FlowFuse Team, allowing you to dive into a given Instance, all from the top-level &amp;quot;Team&amp;quot; view.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the improved audit log view&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/audit-log-child-events.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the improved audit log view&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For a full list of everything that went into our 2.11 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.11.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.10, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have an Enterprise license please make sure to review this &lt;a href=&quot;https://flowfuse.com/changelog/2024/08/enterprise-license-update/&quot;&gt;changelog entry&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/flowfuse-release-2-11/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/</id>
        <title>Why UNS needs Pub/Sub</title>
        <summary>Discover How Pub/Sub Transforms Unified Namespace into a Scalable, Real-Time Data Powerhouse for Modern Manufacturing.</summary>
        <updated>2024-11-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;As the manufacturing industry evolves and becomes increasingly connected through the Industrial Internet of Things (IIoT), the concept of a Unified Namespace (UNS) has emerged as a critical architecture for centralizing and organizing data. UNS serves as a central reference point where all operational data, from machines to the enterprise, can be accessed in a consistent and structured way. Over time, more and more manufacturers have adopted UNS to simplify data integration and improve real-time visibility across systems.&lt;/p&gt;
&lt;p&gt;If you&#39;re unfamiliar with UNS, please read our &lt;a href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/&quot;&gt;Introduction to Unified Namespace&lt;/a&gt; for a basic understanding of UNS.&lt;/p&gt;
&lt;p&gt;If you&#39;re familiar with or already using a UNS, you might be asking: &lt;strong&gt;Why does a UNS need Pub/Sub&lt;/strong&gt;? Here, we’ll explore how combining the Pub/Sub model with a Unified Namespace can help manufacturers streamline data flow, reduce latency, and enable more responsive and scalable operations.&lt;/p&gt;
&lt;h2 id=&quot;what-is-pub%2Fsub%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#what-is-pub%2Fsub%3F&quot;&gt;What is Pub/Sub?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before discussing why Publish/Subscribe (Pub/Sub) is essential for a UNS, let&#39;s first define the Pub/Sub model.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Publish Subscribe Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/pub-sub.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Publish Subscribe Model&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Pub/Sub model is a way for systems to communicate where one component, called the publisher, sends messages to a central system ( Broker such as &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/node-red/protocol/amqp/&quot;&gt;RabitMQ&lt;/a&gt;, and &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka&lt;/a&gt; ), and other components, called subscribers, receive those messages. The publisher doesn’t need to know who the subscribers are, and the subscribers don’t know who the publishers are. The central system, or broker, ensures the right messages go to the right subscribers based on their interests.&lt;/p&gt;
&lt;p&gt;Additionally, it’s important to note that the roles of publisher and subscriber are not mutually exclusive. A component can act as a publisher in one context, sending messages to the broker, and as a subscriber in another, receiving messages from the broker.&lt;/p&gt;
&lt;h2 id=&quot;why-does-a-uns-need-pub%2Fsub%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#why-does-a-uns-need-pub%2Fsub%3F&quot;&gt;Why Does a UNS Need Pub/Sub?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you have a basic understanding of Pub/Sub, let’s dive into why this architecture is essential for a Unified Namespace.&lt;/p&gt;
&lt;h3 id=&quot;decoupling-producers-and-consumers-with-flexible-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#decoupling-producers-and-consumers-with-flexible-communication&quot;&gt;Decoupling Producers and Consumers with Flexible Communication&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In traditional manufacturing setups, various systems and machines often operate in silos, requiring point-to-point connections for communication. This means each device or system must be directly linked to others, which quickly becomes complex and cumbersome as the number of systems grows. Point-to-point integrations are hard to scale because each new device needs a dedicated connection. This not only makes data harder to access but also blocks innovation by creating dependencies between systems.&lt;/p&gt;
&lt;p&gt;To learn more about how point-to-point systems restrict innovation, please read the article: &lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/&quot;&gt;Why the Automation Pyramid Blocks Digital Transformation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Pub/Sub model provides a more scalable solution. In this model, publishers (such as IoT devices or machines) generate data and send it to a central system. Subscribers (other systems, applications, or users) then receive only the data relevant to them. Crucially, the publishers and subscribers do not need to know about each other, relying instead on a central Namespace to distribute the data efficiently.&lt;/p&gt;
&lt;p&gt;By using Pub/Sub in a UNS, industries can create a single reference point for all data, enabling systems to subscribe to the data streams they need, without direct connections to every other system. For example, a production line monitoring system can easily access data from temperature sensors, pressure gauges, and robotic arms without the need for complex point-to-point integrations.&lt;/p&gt;
&lt;p&gt;Unlike point-to-point systems, the Pub/Sub model allows for flexible communication—whether one-to-one, one-to-many, or many-to-many—without the need for direct connections between each system. This flexibility ensures that as your factory evolves, new devices and applications can easily be integrated into the UNS, driving innovation.&lt;/p&gt;
&lt;h3 id=&quot;event-driven-and-asynchronous-communication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#event-driven-and-asynchronous-communication&quot;&gt;Event-driven and Asynchronous Communication&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Pub/Sub model is particularly well-suited for event-driven architectures, where systems react to changes in data rather than periodically polling for updates. This is important in environments where responsiveness is key—such as in predictive maintenance, supply chain optimization, or automated decision-making.&lt;/p&gt;
&lt;p&gt;For instance, a predictive maintenance system can subscribe to real-time sensor data from machines in a UNS. When the system detects an anomaly (e.g., a machine vibration out of normal parameters), it can immediately trigger an alert or maintenance action. This type of asynchronous communication is more efficient and scalable than synchronous polling or direct communication between producers and consumers.&lt;/p&gt;
&lt;h3 id=&quot;less-delay%2C-more-efficiency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#less-delay%2C-more-efficiency&quot;&gt;Less Delay, More Efficiency&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In industries where IIoT-enabled operations are prevalent, real-time data is essential for effective decision-making. Traditional systems often introduce delays due to multiple layers of data collection, storage, and processing. These delays can result in inefficiencies such as slow machine adjustments, missed production targets, or equipment failures.&lt;/p&gt;
&lt;p&gt;The Pub/Sub model reduces latency by immediately pushing data to subscribers as soon as it’s available. There’s no need for systems to poll or wait for periodic updates. Instead, they can respond to real-time events as soon as they occur.&lt;/p&gt;
&lt;p&gt;For instance, in a smart factory, if a machine’s temperature exceeds a threshold, a maintenance system could instantly react by scheduling a technician, triggering an alert, or even pausing operations. Without Pub/Sub, the system would have to rely on polling mechanisms, which are less efficient and often introduce unnecessary delays.&lt;/p&gt;
&lt;p&gt;In real-time environments, these immediate actions can make the difference between preventing costly downtime or catching a problem too late.&lt;/p&gt;
&lt;h3 id=&quot;easy-to-scale-as-you-grow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#easy-to-scale-as-you-grow&quot;&gt;Easy to Scale as You Grow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Manufacturers are always expanding—whether by adding more machines to the production line, introducing new automation systems, or scaling up to handle more products or more data. Scaling traditional systems to keep up with this growth can be complex and costly, especially when new devices or technologies need to be integrated.&lt;/p&gt;
&lt;p&gt;The beauty of Pub/Sub is that it scales effortlessly. When new machines or sensors are introduced, they simply publish their data to the namespace. No complex reconfiguration or integration is required. Similarly, if a new application needs to access this data, it can simply subscribe to the relevant streams.&lt;/p&gt;
&lt;p&gt;For example, consider a car manufacturer adding new robotic arms to the production line. These robots can publish real-time performance data, such as arm movement speeds, energy consumption, and fault alerts, directly into the UNS. The factory’s existing data systems can then subscribe to this new data without requiring changes to the entire system, making integration quick and cost-effective.&lt;/p&gt;
&lt;p&gt;This level of scalability helps manufacturers keep up with growth without worrying about complex system upgrades or slowdowns.&lt;/p&gt;
&lt;h3 id=&quot;making-your-systems-more-reliable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#making-your-systems-more-reliable&quot;&gt;Making Your Systems More Reliable&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In manufacturing, system downtime is costly. However traditional, monolithic systems often rely on point-to-point connections, which can create vulnerabilities. If one part of the system goes down, it can bring down other systems or halt production entirely.&lt;/p&gt;
&lt;p&gt;With a Pub/Sub architecture, this is less of a concern. If one publisher (like a sensor or machine) fails or goes offline, the rest of the systems can continue operating as normal. Other sensors or machines can continue to send their data, and subscribers can still receive real-time updates from other sources.&lt;/p&gt;
&lt;p&gt;Consider a delivery system in a Point-to-Point setup, all vehicles send data directly to a central dispatch system. If the central dispatch system fails, data from all vehicles is lost. In a Pub/Sub setup, vehicles send their data to a central namespace instead of directly to the dispatch system. If the central dispatch system fails, it doesn’t result in data loss. Vehicles can still send their updates.&lt;/p&gt;
&lt;p&gt;This decoupling of systems improves resilience, meaning that your factory can continue running smoothly even if individual components experience issues.&lt;/p&gt;
&lt;p&gt;While the broker is a critical part of the Pub/Sub system and can also go down, this risk can be mitigated. Strategies such as high-availability brokers, failover mechanisms, and clustered deployments can be implemented to prevent downtime and ensure uninterrupted data flow.&lt;/p&gt;
&lt;h3 id=&quot;taking-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#taking-action&quot;&gt;Taking Action&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we&#39;ve discussed, the Pub/Sub model is a game-changer for Unified Namespace architectures in the manufacturing industry. One of the most widely adopted protocols for implementing Pub/Sub is MQTT (Message Queuing Telemetry Transport). MQTT is known for its simplicity, efficiency, and low-bandwidth requirements, making it an ideal choice for Industrial applications.&lt;/p&gt;
&lt;p&gt;To help you leverage the power of MQTT in your manufacturing operations along with Node-RED, Flowfuse offers a robust MQTT broker service. Now, Flowfuse will not only help you build, scale, and manage Node-RED solutions, collaborate across teams, and manage edge devices, but it will also simplify your integration of IIoT data streams into your Unified Namespace. For more information on how our FlowFuse MQTT broker Service, read our &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta%20mqtt%20announcement&amp;amp;utm_term=high_intent&amp;amp;utm_content=Why%20UNS%20needs%20Pub%2FSub/&quot;&gt;MQTT Broker Service Announcement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Get started with this article &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Building UNS with FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/why-pub-sub-in-uns/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating Pub/Sub with a Unified Namespace enhances manufacturing operations by enabling real-time data flow, reducing latency, and improving scalability. This combination ensures efficient, resilient, and future-ready systems, empowering manufacturers to stay competitive in the IIoT era.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/esp32-with-node-red/</id>
        <title>Interacting with ESP32 Using Node-RED and MQTT</title>
        <summary>Building IoT Flows with ESP32 and FlowFuse</summary>
        <updated>2024-11-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/esp32-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;The ESP32 is an affordable and powerful microchip that combines Wi-Fi and Bluetooth in one small package. It&#39;s commonly used in smart devices like home automation systems, wearables, and other IoT projects. Despite its low cost (around $6), it offers strong performance, and low power consumption, and is compatible with popular platforms like Arduino. Whether you&#39;re a hobbyist or a business, the ESP32 provides great value, making it easy to create wireless devices without a big investment. This tutorial demonstrates how to set up communication between the ESP32 and Node-RED using MQTT, along with an interactive dashboard via FlowFuse for a user-friendly interface.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;ecfJ-9MxyVE&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To follow this tutorial, you&#39;ll need the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESP32 microcontroller&lt;/strong&gt;: The hardware you&#39;ll be using for this project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USB cable&lt;/strong&gt;: To connect the ESP32 to your computer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arduino IDE&lt;/strong&gt;: Installed and set up to program your ESP32. &lt;a href=&quot;https://support.arduino.cc/hc/en-us/articles/360019833020-Download-and-install-Arduino-IDE&quot;&gt;Download&lt;/a&gt; the Arduino IDE if you haven&#39;t already done so.
&lt;ul&gt;
&lt;li&gt;Additionally, if you haven&#39;t set up the Arduino IDE for the ESP32 board, please follow this tutorial: &lt;a href=&quot;https://www.youtube.com/watch?v=CD8VJl27n94&quot;&gt;How to Set Up ESP32 with Arduino IDE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse account&lt;/strong&gt;: This will allow you to create and deploy Node-RED instances securely on the cloud with a single click, collaborate on your Node-RED projects with your team, manage and program your edge devices remotely, and provide an MQTT broker with an interface for securely managing clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you haven’t signed up for a FlowFuse account yet, &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Interacting%20with%20ESP32%20Using%20Node-RED%20and%20MQTT&quot;&gt;sign up&lt;/a&gt; now.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-with-esp32-and-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#getting-started-with-esp32-and-node-red&quot;&gt;Getting Started with ESP32 and Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we’ll set up Node-RED on FlowFuse, create an MQTT connection, and configure everything to interact with your ESP32. This will lay the foundation for building your IoT flows and controlling devices.&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-creating-node-red-instance-on-flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#step-1%3A-creating-node-red-instance-on-flowfuse-cloud&quot;&gt;Step 1: Creating Node-RED instance on FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start by logging into your &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; account and creating a new Node-RED instance. For more information on creating a Node-RED instance, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/introduction/#creating-a-node-red-instance&quot;&gt;FlowFuse documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the instance is created, open the Node-RED editor.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-creating-and-configuring-mqtt-clients-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#step-2%3A-creating-and-configuring-mqtt-clients-in-flowfuse&quot;&gt;Step 2: Creating and Configuring MQTT Clients in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this step, we’ll set up MQTT to enable communication between Node-RED and the ESP32. MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for reliable, low-bandwidth communication between devices in IoT applications.&lt;/p&gt;
&lt;p&gt;We use MQTT because it allows devices to communicate over a network (like Wi-Fi) without the need for a direct physical connection. This makes it perfect for long-distance communication, where devices need to send and receive data efficiently, even when they are not physically connected or close to each other.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Diagram showing the flow of data and how commands are sent to the ESP32 using MQTT using Node-RED.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/esp32-mqtt-node-red.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Diagram showing the flow of data and how commands are sent to the ESP32 using MQTT using Node-RED&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In our setup, Node-RED will publish commands to the MQTT broker, and the ESP32 will subscribe to topics to receive responses. The ESP32 will then perform actions, such as controlling an LED. To facilitate this, we’ll create two MQTT clients in FlowFuse (since the MQTT broker is already set up and managed by FlowFuse, you don’t need to worry about its configuration or maintenance). One client will be for Node-RED, and the other will be for the ESP32. These clients will handle the secure and reliable exchange of messages, ensuring smooth communication between the two devices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To Create MQTT Clients in FlowFuse:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your FlowFuse platform and log in to your account.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click on &amp;quot;Broker&amp;quot;.&lt;/li&gt;
&lt;li&gt;In the newly opened interface, click the “Create Client” button.&lt;/li&gt;
&lt;li&gt;Enter a username and password for your MQTT client. Confirm the password.
&lt;ul&gt;
&lt;li&gt;You can leave the default pattern as &lt;code&gt;#&lt;/code&gt; for access control, or set a custom pattern if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Interface for setting MQTT client details and credentials&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-client-create.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Interface for setting MQTT client details and credentials&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Click &amp;quot;Create&amp;quot; to generate the client.&lt;/li&gt;
&lt;li&gt;Copy the client ID and save it somewhere secure for later use.&lt;/li&gt;
&lt;li&gt;Repeat the same steps to create the second MQTT client for the ESP32.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-3%3A-building-a-node-red-dashboard-to-send-commands-over-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#step-3%3A-building-a-node-red-dashboard-to-send-commands-over-mqtt&quot;&gt;Step 3: Building a Node-RED Dashboard to Send Commands Over MQTT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we’ve created the MQTT clients, it’s time to build a Node-RED dashboard and create a flow that will publish commands to the FlowFuse MQTT broker. This will later allow you to interact with your ESP32 using a user-friendly interface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let&#39;s first create a flow to connect to the MQTT broker with the client config we have created:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;mqtt out&lt;/strong&gt; node onto the canvas in Node-RED.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;mqtt out&lt;/strong&gt; node to open the settings.&lt;/li&gt;
&lt;li&gt;Click the pencil icon next to the Server field to open the MQTT broker configuration.&lt;/li&gt;
&lt;li&gt;In the configuration, enter the following details:
&lt;ul&gt;
&lt;li&gt;Server: &lt;code&gt;broker.flowfuse.cloud&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Client ID: The Client ID you created earlier.&lt;/li&gt;
&lt;li&gt;Username: The MQTT username (Client ID).&lt;/li&gt;
&lt;li&gt;Password: The MQTT password.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Add&amp;quot; to save the configuration, then select the newly added configuration.&lt;/li&gt;
&lt;li&gt;In the Topic field, enter a topic name, such as &lt;code&gt;/LEDControl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Done&amp;quot; to close the settings.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Deploy&amp;quot; in the top-right corner to deploy the flow.&lt;/li&gt;
&lt;li&gt;Once deployed, check the MQTT out node for a Connected status, confirming the connection to the MQTT broker.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this example, we will create a very simple dashboard. If you&#39;re not familiar with FlowFuse Dashboard, you can refer to the following blog to get started: &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;FlowFuse Dashboard: Getting Started&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; from the Node-RED Palette Manager.&lt;/li&gt;
&lt;li&gt;Drag two &lt;strong&gt;ui-button&lt;/strong&gt; widgets onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the first button and set the Label to &amp;quot;ON&amp;quot;, the Background Color to Green, and the Payload to &lt;code&gt;1&lt;/code&gt;. Adjust the Width and Height as needed.&lt;/li&gt;
&lt;li&gt;Double-click on the second button and set the Label to &amp;quot;OFF&amp;quot;, the Background Color to Red, and the Payload to &lt;code&gt;2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Connect the output of both buttons to the input of the &lt;strong&gt;mqtt out&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Deploy&amp;quot; to save the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-200&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow200 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;59887a8115c95eae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Flow 1&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;02c25e8a30f9379d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;appIcon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:true,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;cfb2ab9ff30660fc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094CE&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;d263574af6876c7a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;ESP32&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;02c25e8a30f9379d&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;cfb2ab9ff30660fc&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;3ae115ea7ede6827&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Group 1&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d263574af6876c7a&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;groupType&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;def97b29f5f7baab&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;broker.flowfuse.cloud&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;autoConnect&#92;&quot;:true,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;autoUnsubscribe&#92;&quot;:true,&#92;&quot;birthTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;birthRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;birthPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthMsg&#92;&quot;:{},&#92;&quot;closeTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;closeRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;closePayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeMsg&#92;&quot;:{},&#92;&quot;willTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;willRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;willPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willMsg&#92;&quot;:{},&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sessionExpiry&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5a9162986a34a4d6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;59887a8115c95eae&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3ae115ea7ede6827&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;ON&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;green&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:true,&#92;&quot;enablePointerdown&#92;&quot;:false,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:false,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9239f8a7cca5c858&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f9c194994d9491a8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;59887a8115c95eae&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3ae115ea7ede6827&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;OFF&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;emulateClick&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconPosition&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;buttonColor&#92;&quot;:&#92;&quot;red&#92;&quot;,&#92;&quot;textColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;iconColor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;enableClick&#92;&quot;:true,&#92;&quot;enablePointerdown&#92;&quot;:false,&#92;&quot;pointerdownPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerdownPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;enablePointerup&#92;&quot;:false,&#92;&quot;pointerupPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pointerupPayloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9239f8a7cca5c858&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9239f8a7cca5c858&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;59887a8115c95eae&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;/LedControl&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retain&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;respTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;contentType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;correl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expiry&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;def97b29f5f7baab&#92;&quot;,&#92;&quot;x&#92;&quot;:390,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow200.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-200&#39;) })&lt;/script&gt;
&lt;p&gt;Now, when you click either the &amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot; button on the dashboard, it will send either 1 or 2 as the payload. The ESP32 will use this payload in its code to turn the LED on or off. To view the dashboard, switch to the Dashboard 2.0 tab on the right side and click the Open Dashboard button. The dashboard will look similar to the image below.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Dashboard Build to control the ESP32 LED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Dashboard Build to control the ESP32 LED&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-4%3A-programming-esp32-to-receive-commands-from-mqtt-and-control-led&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#step-4%3A-programming-esp32-to-receive-commands-from-mqtt-and-control-led&quot;&gt;Step 4: Programming ESP32 to receive commands from MQTT and Control LED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&#39;s move on to the final step. Before proceeding, make sure your ESP32 is &lt;strong&gt;connected to your laptop or computer via USB&lt;/strong&gt;*. The USB connection is essential for uploading the code (sketch) to the ESP32, which will enable it to connect to the internet and communicate with the MQTT broker.
The ESP32 will subscribe to the MQTT topic we configured earlier (e.g., /LEDControl). Based on the received payload (1 or 2), it will control the LED accordingly — turning it on or off.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting up Arduino IDE:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Arduino IDE on your computer.&lt;/li&gt;
&lt;li&gt;Ensure you have selected the correct board and port in the Tools menu.&lt;/li&gt;
&lt;li&gt;Install the necessary library:&lt;/li&gt;
&lt;li&gt;Go to Tools &amp;gt; &amp;quot;Manage Libraries&amp;quot;.&lt;/li&gt;
&lt;li&gt;Search for and install the &amp;quot;EspMQTTClient&amp;quot; library by Patrick Lapointe.&lt;/li&gt;
&lt;li&gt;The library installation will prompt you to install its dependencies—ensure that you tick that option and proceed to install.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Code for ESP32:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy the following code into the Arduino IDE:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-297&quot;&gt;
  &lt;pre class=&quot;language-cpp&quot;&gt;&lt;code id=&quot;code-297&quot; class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;defined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ESP32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;WiFi.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;defined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ESP8266&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;ESP8266WiFi.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;PubSubClient.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;LedPin&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// ESP32 built-in LED pin&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// WiFi and MQTT settings&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; ssid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Change this to your WiFi SSID&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; password &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Change this to your WiFi password&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; mqtt_server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;broker.flowfuse.cloud&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// FlowFuse MQTT broker server&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// MQTT client credentials&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; mqtt_client_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Replace with your MQTT client ID&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; mqtt_username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Replace with your MQTT username&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; mqtt_password &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Replace with your MQTT password&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WiFiClient espClient&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;PubSubClient &lt;span class=&quot;token function&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;espClient&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Function to connect to WiFi&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setup_wifi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Connecting to &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ssid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    WiFi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ssid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WiFi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; WL_CONNECTED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;nWiFi connected&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;IP address: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WiFi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localIP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Callback function to handle messages from subscribed topics&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; byte&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; String msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; msg &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// Control LED based on message&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LedPin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HIGH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Turn LED on&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LedPin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LOW&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Turn LED off&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Function to connect to MQTT broker&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reconnect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Attempting MQTT connection...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// Connect to MQTT broker with the client ID, username, and password&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mqtt_client_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mqtt_username&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mqtt_password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Connected to MQTT broker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/LedControl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed, rc=&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; trying again in 5 seconds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Serial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;115200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;pinMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LedPin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; OUTPUT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;setup_wifi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mqtt_server&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1883&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;reconnect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-297&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Replace the placeholder values in the code: SSID (your Wi-Fi network&#39;s SSID), Wi-Fi Password (your Wi-Fi network&#39;s password), MQTT Client ID (the MQTT client ID you generated for esp32), MQTT Username and Password (the MQTT credentials you created).&lt;/li&gt;
&lt;li&gt;After you&#39;ve made these changes, click &amp;quot;Upload&amp;quot; in the Arduino IDE to upload the code to your ESP32.&lt;/li&gt;
&lt;li&gt;Once the upload is complete, open the Serial Monitor (set the baud rate to 115200) to monitor the output.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If everything is set up correctly, you should see the output in the Serial Monitor as shown in the image.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Serial monitor displaying the result when everything is set up correctly.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/serial-monitor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Serial monitor displays the result when everything is set up correctly.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once you verify the setup, you can unplug the USB from the computer and connect the ESP32 to a power adapter. With this, your ESP32 is now powered and connected to Wi-Fi (make sure your device is on the same Wi-Fi network as the one configured in the code), allowing you to control the LED from anywhere in the world via the MQTT commands sent through Node-RED.&lt;/p&gt;
&lt;h3 id=&quot;troubleshooting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Can&#39;t Upload Code to ESP32&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Solution: Make sure the correct board and port are selected in the Arduino IDE.
Check Tools &amp;gt; Board for the right ESP32 model and Tools &amp;gt; Port for the correct connection.
If the port is missing, &lt;a href=&quot;https://www.silabs.com/developer-tools/usb-to-uart-bridge-vcp-drivers?tab=downloads&quot;&gt;Download&lt;/a&gt; and reinstall the CP210x USB drivers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ESP32 Keeps Disconnecting from MQTT&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Solution: Make sure both the ESP32 and Node-RED have unique MQTT client IDs.
If both devices share the same client ID, they will conflict and cause disconnections.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;ESP32 Doesn’t Respond to Commands (LED Not Turning On/Off)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Solution: Verify the topic in the ESP32 code matches the one in Node-RED (e.g., /LedControl). If it still doesn&#39;t work, try rebooting your ESP32.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/esp32-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this tutorial, we successfully connected the ESP32 to Node-RED using MQTT, enabling remote control of an LED via a FlowFuse dashboard. This simple IoT setup demonstrates how easy it is to interact with devices using MQTT and Node-RED, offering a flexible and scalable solution for future projects. With the ESP32, Node-RED, and FlowFuse, you can easily expand and integrate more devices into your IoT system.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/</id>
        <title>Migrating from Self-Managed Node-RED to FlowFuse-Managed Node-RED</title>
        <summary>A Step-by-Step Guide to Transitioning Your Node-RED Flows to a Streamlined FlowFuse Environment</summary>
        <updated>2024-11-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Migrating your Node-RED instance to &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; centralizes management and simplifies deployment. Once migrated, FlowFuse takes care of the infrastructure, security, and scalability, making the process much easier. This allows you to focus on building solutions without worrying about the complexities of self-hosting. Whether you&#39;re working with edge devices or want to work on cloud instances, this migration streamlines the management of your IIoT workflows, improving efficiency and scalability.&lt;/p&gt;
&lt;p&gt;Let&#39;s explore how to migrate from a self-managed and self-hosted Node-RED setup to a FlowFuse-managed environment. We&#39;ll look at how the migration works for both edge devices and cloud instances.&lt;/p&gt;
&lt;h2 id=&quot;why-switch-from-self-managed-node-red-to-flowfuse-managed-node-red%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#why-switch-from-self-managed-node-red-to-flowfuse-managed-node-red%3F&quot;&gt;Why Switch from Self-Managed Node-RED to FlowFuse-Managed Node-RED?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing self-hosted Node-RED instances can introduce a range of challenges, especially as your Industrial Internet of Things (IIoT) environment scales. These challenges include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Complexity&lt;/strong&gt;: Installing and configuring Node-RED across multiple devices or environments requires technical expertise and attention to detail. For large-scale deployments, managing numerous instances across different devices or servers can become cumbersome and error-prone.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security and Maintenance&lt;/strong&gt;: Ensuring your Node-RED instances are secure and up-to-date requires continuous monitoring, timely security patches, and ongoing maintenance. Keeping instances stable and secure can be time-consuming and requires dedicated resources to avoid vulnerabilities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: As your IIoT environment grows, scaling your Node-RED infrastructure to handle increased workloads can be challenging. Managing multiple distributed instances often leads to inconsistencies and difficulties in maintaining optimal performance across your entire system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Edge Device Management&lt;/strong&gt;: Managing Node-RED instances on edge devices introduces additional complexity. Remote access, secure monitoring, and seamless updates become more difficult as your network expands, especially when dealing with a large number of edge devices.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse addresses these challenges by providing a fully managed, secure, and scalable environment for your Node-RED instances. With FlowFuse, you can focus on building and deploying your IIoT solutions, while FlowFuse handles the infrastructure, updates, and scalability. This reduces operational overhead and ensures your instances remain up-to-date and secure.&lt;/p&gt;
&lt;p&gt;For more information, read the article: &lt;a href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/&quot;&gt;Transform Chaos into Control: Centralize Node-RED Management with FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;migrating-from-node-red-to-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#migrating-from-node-red-to-flowfuse&quot;&gt;Migrating from Node-RED to FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have a FlowFuse Account created. Next, consider how your Node-RED instance needs to be deployed. Decide whether it should run on the edge device or as a cloud instance.&lt;/p&gt;
&lt;p&gt;Running Node-RED on an edge device is ideal when your application flow needs direct access to hardware components, such as reading sensors or controlling actuators. This setup allows immediate data processing and control, crucial for applications requiring low latency responses.&lt;/p&gt;
&lt;p&gt;On the other hand, if your use case involves monitoring or collecting metrics—such as through MQTT—without needing direct hardware interaction, and you primarily need to transform, contextualize, visualize, or automate repetitive tasks that don&#39;t require hardware interaction, a &lt;strong&gt;Cloud Instance&lt;/strong&gt; may be more suitable. This option allows you to centralize data collection and processing, making it easier to manage and analyze data from multiple devices.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The instructions provided in this article also work for &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;self-hosted&lt;/a&gt; FlowFuse environments. Just ensure that when following the steps, you&#39;re performing the actions within your self-hosted FlowFuse setup rather than the FlowFuse cloud platform.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;creating-a-cloud-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#creating-a-cloud-instance&quot;&gt;Creating a Cloud Instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The FlowFuse snapshot feature, available through the &lt;code&gt;@flowfuse/nr-tools-plugin&lt;/code&gt; for self-managed Node-RED (a plugin that allows you to create snapshots from a self-managed Node-RED instance to the FlowFuse platform), However, it does not support direct device snapshots. Instead, you must first create a snapshot for the Cloud Instance and then assign it as the target for your device.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the FlowFuse platform and log in to your account.&lt;/li&gt;
&lt;li&gt;Select the application under which you want to manage your Node-RED instance. You can either choose the default application created with your account or click the &amp;quot;Create Application&amp;quot; button to create a new one.&lt;/li&gt;
&lt;li&gt;Once inside the application, select &amp;quot;Add Instance.&amp;quot;&lt;/li&gt;
&lt;li&gt;Enter a name (or let the system generate one automatically), select the instance type, and choose the Node-RED version that matches your current setup.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Create&amp;quot; to launch the instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;creating-a-device-instance-and-connecting-it-to-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#creating-a-device-instance-and-connecting-it-to-flowfuse&quot;&gt;Creating a Device Instance and Connecting It to FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you need to run Node-RED on the edge device itself but want to manage it remotely, follow the steps below. Skip this step if your Node-RED Application flow can run on the cloud.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the cloud instance you created above.&lt;/li&gt;
&lt;li&gt;Go to the &amp;quot;Devices&amp;quot; tab by clicking on top &amp;quot;Devices&amp;quot; option and select &amp;quot;Add Device&amp;quot;.&lt;/li&gt;
&lt;li&gt;Once you click &amp;quot;Add Device&amp;quot;, a device configuration popup will appear. Copy the command provided and save it for later.&lt;/li&gt;
&lt;li&gt;Follow the steps to install the FlowFuse Device Agent on your device as given in this &lt;a href=&quot;https://flowfuse.com/docs/device-agent/install/&quot;&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Execute the saved command on the device.&lt;/li&gt;
&lt;li&gt;Start the FlowFuse device agent by executing the following command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-126&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-126&quot; class=&quot;language-bash&quot;&gt;   flowfuse-device-agent &lt;span class=&quot;token parameter variable&quot;&gt;--port&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1881&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-126&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Running on port &lt;code&gt;1881&lt;/code&gt; ensures it doesn&#39;t conflict with your locally running Node-RED instance, allowing both to run without issues.&lt;/p&gt;
&lt;h3 id=&quot;creating-essential-backups-before-migration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#creating-essential-backups-before-migration&quot;&gt;Creating Essential Backups Before Migration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Creating a cloud instance is essential for the migration process, regardless of whether your Node-RED instance will run on the device or on the cloud. As discussed earlier, the &lt;code&gt;@flowfuse/nr-tools-plugin&lt;/code&gt; does not support creating direct snapshots for devices on the platform. Therefore, you must first create a snapshot for the cloud instance before deploying it to the device.&lt;/p&gt;
&lt;p&gt;Follow these steps to create a cloud instance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;@flowfuse/nr-tools-plugin&lt;/code&gt; into your Node-RED instance via the Palette Manager.&lt;/li&gt;
&lt;li&gt;Once installed, open the &amp;quot;FlowFuse tools&amp;quot; tab in the sidebar.&lt;/li&gt;
&lt;li&gt;Connect to your FlowFuse Cloud account by clicking the &amp;quot;Connect to FlowFuse&amp;quot; button.&lt;br /&gt;
&lt;em&gt;(If you&#39;re migrating to a self-hosted FlowFuse instance, ensure you configure the plugin with the correct URL. For detailed steps, refer to the &lt;a href=&quot;https://flowfuse.com/docs/migration/node-red-tools/#connecting-to-flowfuse&quot;&gt;FlowFuse Node-RED Tools plugin Documentation&lt;/a&gt;)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A browser popup will appear, prompting you to log in to your FlowFuse account. Click &amp;quot;Allow&amp;quot; to grant permission.&lt;/li&gt;
&lt;li&gt;After successful authorization, you&#39;ll be able to select your team and the associated instance from the &amp;quot;FlowFuse tools&amp;quot; tab.&lt;/li&gt;
&lt;li&gt;Choose the team and FlowFuse instance you want to migrate to or the one you will use to take snapshots for your device.&lt;/li&gt;
&lt;li&gt;Click the &amp;quot;+ Snapshot&amp;quot; button to create a snapshot. A popup will appear asking for a name and description. Enter the required details and click &amp;quot;Create&amp;quot;.&lt;/li&gt;
&lt;li&gt;Once the snapshot is created, it will be listed in the sidebar.&lt;/li&gt;
&lt;li&gt;To verify, navigate to the FlowFuse platform, go to the FlowFuse Cloud instance you created earlier, and switch to the &amp;quot;Snapshots&amp;quot; tab. The snapshot you created should be visible there.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;backing-up-system-level-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#backing-up-system-level-environment-variables&quot;&gt;Backing Up System-level Environment Variables&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;While the snapshot captures flows, credentials, and environment variables at the flow and global level, it does not capture &lt;strong&gt;process environment variables&lt;/strong&gt;—those set in the Node-RED &lt;code&gt;settings.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;To get these variables, you can use the following flow to dump a list of all process environment variables into the debug window:&lt;/p&gt;
&lt;div id=&quot;nr-flow-201&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow201 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;3ed886625239a5d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;a87879f70edc3463&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;process.env&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;msg.payload = process.env&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[{&#92;&quot;var&#92;&quot;:&#92;&quot;process&#92;&quot;,&#92;&quot;module&#92;&quot;:&#92;&quot;process&#92;&quot;}],&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9ca3edbd6857853f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b35ef390a46ff129&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;a87879f70edc3463&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;List env vars&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3ed886625239a5d0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9ca3edbd6857853f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;a87879f70edc3463&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow201.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-201&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;Import and deploy the flow into your self-managed Node-RED instance.&lt;/li&gt;
&lt;li&gt;Click the Inject Node&#39;s button&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once clicked, the flow will print all environment variables in the debug window. Identify the environment variables required for your flow and save them in a notepad for later use.&lt;/p&gt;
&lt;h4 id=&quot;setting-system-level-environment-variables-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#setting-system-level-environment-variables-in-flowfuse&quot;&gt;Setting System-Level Environment Variables in FlowFuse&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now that you have created the snapshots and copied the process environment variables, you need to set these variables in the Node-RED instance to avoid errors during deployment and smooth application running.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the your FlowFuse Cloud/Device instance.&lt;/li&gt;
&lt;li&gt;Open the Settings tab by clicking the &amp;quot;Settings&amp;quot; option at the top of the page, then select the Environment tab.&lt;/li&gt;
&lt;li&gt;Add the environment variables one by one by clicking the &amp;quot;+ Add&amp;quot; button in the bottom-left corner.&lt;/li&gt;
&lt;li&gt;After adding all the environment variables, click &amp;quot;Save.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information refer to &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;migrating-static-assets-to-flowfuse-static-assets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#migrating-static-assets-to-flowfuse-static-assets&quot;&gt;Migrating Static Assets to FlowFuse Static Assets&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When working with dashboards or files required in your Node-RED project, these files are typically stored locally and are always available, even if you restart or modify the flows. However, when migrating from Node-RED to a FlowFuse cloud environment, you&#39;ll need to manually migrate these files to the cloud-based Node-RED instances. To make this process easier, FlowFuse offers a static assets service feature at the instance level.&lt;/p&gt;
&lt;p&gt;Here’s how you can migrate your assets:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Locate your static assets in your local system that are used in your Self-managed Node-RED instance from the snapshot we have taken.&lt;/li&gt;
&lt;li&gt;Upload them one by one through the Instance &amp;quot;Static Assets&amp;quot; tab. For more information, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/static-asset-service/&quot;&gt;Static Asset Service documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you have migrated all your assets, you will be able to access them in the instance created in the FlowFuse cloud. Just ensure that after deploying the snapshot, the path set in the flow matches the static assets migrated to the FlowFuse instance.&lt;/p&gt;
&lt;h3 id=&quot;deploying-snapshot-for-the-cloud%2Fdevice-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#deploying-snapshot-for-the-cloud%2Fdevice-instance&quot;&gt;Deploying Snapshot for the Cloud/Device instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the system-level environment variables are set and all static assets have been migrated ( if your Node-RED application flow is using static assets), you can deploy the captured snapshot to either the Cloud or Device instance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the FlowFuse Cloud instance where you created the snapshot by clicking &amp;quot;Hosted Instance&amp;quot; in the left sidebar and selecting the instance from the list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to the &amp;quot;Snapshots&amp;quot; tab at the top to locate the snapshot you created from the list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the right side of the snapshot, click the three-dot icon:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you are migrating to the Cloud Instance, select &lt;strong&gt;&amp;quot;Restore Snapshot&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;If you are migrating to a Device Instance, select &lt;strong&gt;&amp;quot;Set as Device Target&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Setting a device target will ensure that the snapshot will be deployed on all of the devices associated with this instance.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/migrating-from-node-red-to-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Migrating from a self-managed Node-RED setup to FlowFuse is simple and offers significant benefits. By transitioning, you’ll reduce operational complexity, enhance security, and improve scalability. FlowFuse handles the infrastructure, so you can focus on building and optimizing your IIoT solutions—whether on edge devices or in the cloud.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/</id>
        <title>Run FlowFuse Device Agent as a service on MacOS using Docker</title>
        <summary>Automating FlowFuse Device Agent on macOS with Docker and Colima.</summary>
        <updated>2024-11-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;The FlowFuse Device Agent is a tool that enables you to run Node-RED on various hardware devices, such as Raspberry Pi, Windows, MacOS, and PLCs. Running Node-RED directly on the device helps when your application flow needs direct access to sensors and actuators connected to the hardware, facilitating seamless integration with the FlowFuse platform. This integration enables secure management, monitoring, and remote editing of flows from a centralized platform, even at the edge.&lt;/p&gt;
&lt;p&gt;In this article, we will explore how to run the FlowFuse Device Agent as a service on MacOS using Docker. This setup ensures that the Device Agent runs in the background, automatically starts on boot, and maintains a continuous connection the FlowFuse platform for remotely managing your Node-RED flows, even after a device restart. This eliminates the need to manually start the agent after each reboot, saving you time and effort.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before starting, ensure that you have the following set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Account&lt;/strong&gt;: You need an active FlowFuse account to register your device and manage your flows remotely. If you don&#39;t have an account, you can &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Run%20FlowFuse%20Device%20Agent%20as%20a%20service%20on%20MacOS%20using%20Docker&quot;&gt;sign up&lt;/a&gt; at FlowFuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;NOTE: The instructions in this guide were tested on MacBook M1 &amp;amp; M4 MacBook Pro&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-1%3A-install-homebrew&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-1%3A-install-homebrew&quot;&gt;Step 1: Install Homebrew&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Homebrew is the MacOS package manager for installing packages and libraries. You can install it using the following command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-28&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-28&quot; class=&quot;language-bash&quot;&gt;/bin/bash &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-28&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This script will install the Homebrew package manager on your Mac. Once installed, you can easily install other packages like Docker and Colima.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-install-docker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-2%3A-install-docker&quot;&gt;Step 2: Install Docker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With Homebrew installed, you can now install Docker by running:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-38&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-38&quot; class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; docker-credential-helper &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-38&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will install Docker and its credential helper, which is useful for managing authentication with Docker registries.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-install-colima&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-3%3A-install-colima&quot;&gt;Step 3: Install Colima&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Colima is a free alternative to Docker Desktop, particularly useful for MacOS, and offers better compatibility with Apple Silicon hardware. We’ll need it to run the Flowfuse Device Agent container that we will create later. To install Colima, run:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-48&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-48&quot; class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; colima&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-48&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-4%3A-start-colima&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-4%3A-start-colima&quot;&gt;Step 4: Start Colima&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once Colima is installed, start it with:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-55&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-55&quot; class=&quot;language-bash&quot;&gt;colima start&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-55&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This command starts the Colima virtual machine, which Docker will then use to run containers. If Colima is not running, Docker won&#39;t have the necessary environment to create and run containers.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-59&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-59&quot; class=&quot;language-bash&quot;&gt;colima status&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-59&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;CLI: Showing the result of `colima status`&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/colima-status.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;CLI: Showing the result of &lt;code&gt;colima status&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-5%3A-set-colima-to-run-as-a-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-5%3A-set-colima-to-run-as-a-service&quot;&gt;Step 5: Set Colima to Run as a Service&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To ensure Colima starts automatically in the background, run the following:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-69&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-69&quot; class=&quot;language-bash&quot;&gt;brew services start colima&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-69&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will set Colima to run as a service, so it will start automatically every time your Mac boots up.&lt;/p&gt;
&lt;h3 id=&quot;step-6%3A-adding-the-device-to-the-flowfuse-platform&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-6%3A-adding-the-device-to-the-flowfuse-platform&quot;&gt;Step 6: Adding the Device to the FlowFuse Platform&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, you&#39;ll need to add a new device to the FlowFuse platform and download the device configuration file. This configuration will allow to connect your MacOS device to your FlowFuse team. For more information on how to add a device and generate the configuration, refer to &lt;a href=&quot;https://flowfuse.com/docs/device-agent/register/&quot;&gt;Generating &amp;quot;Device Configuration&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-7%3A-run-the-flowfuse-device-agent-container&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-7%3A-run-the-flowfuse-device-agent-container&quot;&gt;Step 7: Run the FlowFuse Device Agent Container&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can now run the FlowFuse Device Agent container using Docker. Replace &lt;code&gt;/path/to/device.yml&lt;/code&gt; with the actual path to the device configuration file you have downloaded. The following command will launch the container:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-85&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-85&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--restart&lt;/span&gt; unless-stopped &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--mount&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;bind,src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/path/to/device.yml,target&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/opt/flowfuse-device/device.yml &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1880&lt;/span&gt;:1880 flowfuse/device-agent:latest&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-85&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Explanation of the command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt;: Run the container in detached mode (in the background).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--restart&lt;/code&gt; unless-stopped: Ensure the container restarts automatically unless explicitly stopped.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--mount type=bind,src=/path/to/device.yml,target=/opt/flowfuse-device/device.yml&lt;/code&gt;: Mounts your local device.yml file into the container so it can be accessed by the agent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p 1880:1880&lt;/code&gt;: Exposes port 1880 on your host machine, which is typically used for the Node-RED web interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flowfuse/device-agent:latest&lt;/code&gt;: The Docker image for the FlowFuse Device Agent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-8%3A-verify-the-device-agent-is-running&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-8%3A-verify-the-device-agent-is-running&quot;&gt;Step 8: Verify the Device Agent is Running&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To verify that the Device Agent is running correctly, you can use the following command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-122&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-122&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ps&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-122&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;CLI: Showing the result of `docker ps` indicating device agent is running correctly&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/docker-ps-result.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;CLI: Showing the result of &lt;code&gt;docker ps&lt;/code&gt; indicating the device agent is running correctly&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This will list all running containers, and you should see the FlowFuse Device Agent listed there. If it&#39;s not running, you can check the logs to troubleshoot:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-129&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-129&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; logs &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;container_id&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-129&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Additionally, you can confirm that the Device Agent is running and successfully connected to the FlowFuse platform by following these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the FlowFuse platform.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click on &amp;quot;Edge Devices&amp;quot;.&lt;/li&gt;
&lt;li&gt;Then, select the device you added for MacOS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;FlowFuse Platform: showing the status of your edge device&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-status-on-ff.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse Platform: showing the status of your edge device&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, you can start developing applications on the device remotely from any location and manage it efficiently.&lt;/p&gt;
&lt;h3 id=&quot;step-9%3A-ensure-the-device-agent-restarts-automatically-after-a-reboot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#step-9%3A-ensure-the-device-agent-restarts-automatically-after-a-reboot&quot;&gt;Step 9: Ensure the Device Agent Restarts Automatically After a Reboot&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;--restart unless-stopped&lt;/code&gt; flag in the Docker command ensures that your FlowFuse Device Agent container will automatically restart if your Mac reboots. However, it&#39;s always good to verify this by restarting your system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Restart your Mac.&lt;/li&gt;
&lt;li&gt;After rebooting, check the status of the FlowFuse Device Agent:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-174&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-174&quot; class=&quot;language-bash&quot;&gt;   &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ps&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-174&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/device-agent-as-service-on-mac/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By following these steps, you&#39;ve successfully set up the FlowFuse Device Agent on your macOS system using Docker and Colima. Now, the agent will run seamlessly in the background and restart automatically after a system reboot.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/</id>
        <title>Visual Layout Editor - Now Available in Dashboard</title>
        <summary>With the latest update we have released a new Layout Editor for Dashboard, as well as new widgets and wide-spread improvements.</summary>
        <updated>2024-11-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It has been one of the most requested features for FlowFuse Dashboard, and is now available in its first iteration. It is now possible to resize and move groups in the Dashboard itself using the new &amp;quot;Edit Layout&amp;quot; feature. That&#39;s not all though, we&#39;ve added a new &amp;quot;Spacer&amp;quot; widget to assist with layouts, added improvements to the rendering of charts and plenty more.&lt;/p&gt;
&lt;h2 id=&quot;layout-editor---quick-guide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/#layout-editor---quick-guide&quot;&gt;Layout Editor - Quick Guide&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For those transitioning over from the original Node-RED Dashboard 1.0, you&#39;ll notice some difference in how you can now edit the layout of your dashboard. Now, the editing is done directly in the Dashboard itself, rather than in the Node-RED editor.&lt;/p&gt;
&lt;p&gt;To open the Dashboard in &amp;quot;Edit Mode&amp;quot;, click the &amp;quot;Edit Layout&amp;quot; button for the relevant page in the Dashboard sidebar:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img width=&quot;500px&quot; data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Edit Layout button in the Dashboard sidebar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-layout-button.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot to show the buttons available to &amp;quot;Edit Layout&amp;quot; for a given page&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This will open the relevant page in &amp;quot;Edit Mode&amp;quot;:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Short recording to show resizing and reordering in the visual layout editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/wysiwyg-demo.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Short recording to show resizing and reordering in the visual layout editor&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The three controls at the top of the page are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Save Changes:&lt;/strong&gt; Deploy any changes to the underlying Node-RED flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discard Changes:&lt;/strong&gt; Clear any in-browser changes that have not yet been saved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exit Edit Mode:&lt;/strong&gt; Stop &amp;quot;Edit Mode&amp;quot; and interact with teh Dashboard as a standard end-user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can then use the handles on each group to resize them, or click and drag to re-position the groups on the page. How this re-positioning is done is controlled by the &amp;quot;Layout&amp;quot; property of the page. The Visual Editor is currently available for &amp;quot;Grid&amp;quot; and &amp;quot;Fixed&amp;quot; layouts only.&lt;/p&gt;
&lt;p&gt;Once you&#39;re happy with your changes clicked the &amp;quot;Save Changes&amp;quot; button to deploy them to the underlying Node-RED flow. Note, you will then be made aware that &lt;em&gt;&amp;quot;your flows have been updated&amp;quot;&lt;/em&gt; by Dashboard when you return to your Node-RED Editor.&lt;/p&gt;
&lt;p&gt;Note that you can only enter &amp;quot;Edit Mode&amp;quot; via the Node-RED Editor, this is to ensure security and stability of your Dashboard, in cases where you may have users for your Dashboard that should not have access to modify your Dashboard&#39;s layout.&lt;/p&gt;
&lt;h2 id=&quot;layout-editor---next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/#layout-editor---next-steps&quot;&gt;Layout Editor - Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are very aware that is this is just the first iteration of the Layout Editor, and we have plenty of plans to improve it further. Here are some of the features we are considering for future releases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Include widget resizing and ordering in the Layout Editor&lt;/li&gt;
&lt;li&gt;Overhauling sizing options for groups and widgets &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/835&quot;&gt;#835&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there are any other key editor features you&#39;d like to see, then please do reach out to us, open GitHub issues and help us shape the future of FlowFuse Dashboard.&lt;/p&gt;
&lt;h2 id=&quot;new-widget%3A-ui-spacer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/#new-widget%3A-ui-spacer&quot;&gt;New Widget: UI Spacer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the Dashboard sidebar, you now have the option to add a &amp;quot;Spacer&amp;quot;, this is just an empty widget that can be used to shift the position of other widgets. This can be useful for creating more complex layouts, or for adding space between widgets. For example, if you wanted to have some directional controls with up/down/left/right buttons, you could use a spacer to separate and align them:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;(left) A d-pad controller layout using spacers, (right) the spacer&#39;s highlighted to demonstrate their positioning&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/spacer-example.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;(left) A d-pad controller layout using spacers, (right) the spacer&#39;s highlighted to demonstrate their positioning&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Spacers can be any width and height, and will always render empty-space. To add a new spacer, you can click the &amp;quot;+&amp;quot; button in the Dashboard sidebar next to any Groups. You can then re-order the widgets there too (re-ordering of widgets in the visual layout editor will be coming soon).&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can find the full 1.19.0 Release Notes &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v1.19.0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Work has already begun on the next release, &lt;code&gt;1.20.0&lt;/code&gt;, you can see what items we have queued up &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;here&lt;/a&gt;, if you&#39;ve got any feedback or suggestions, please do let us know, and feel free to open new issues on our &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;we-are-hiring!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/11/dashboard-new-group-type-app-icon-and-charts/#we-are-hiring!&quot;&gt;We are Hiring!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may have seen already that we are hiring for a full-time Front-End Engineer to join our team, and work on Dashboard, full-time. If you are interested in working with us, please do check out the job listing &lt;a href=&quot;https://job-boards.greenhouse.io/flowfuse/jobs/5185319004&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/</id>
        <title>MQTT Service Now Available on FlowFuse</title>
        <summary>We are thrilled to announce a significant milestone for FlowFuse, we now offer our very own MQTT service, built-in and ready to use with your Node-RED applications.</summary>
        <updated>2024-10-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;In our &lt;a href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/&quot;&gt;recent product update&lt;/a&gt; we have added our very own MQTT service, built-in and ready to use alongside your Node-RED applications. We are always engaging with users and prospective customers and this has been a highly requested feature, and so we are delighted to announce that this is now live on FlowFuse Cloud for our Pro and Enterprise teams.&lt;/p&gt;
&lt;p&gt;The MQTT Service is available now on &lt;a href=&quot;https://flowfuse.com/platform/cloud/&quot;&gt;FlowFuse Cloud&lt;/a&gt;. FlowFuse permits you to setup your own secure clients to begin publishing and subscribing to your own topics.&lt;/p&gt;
&lt;p&gt;You can now use FlowFuse to manage your own MQTT Clients alongside your Node-RED instances, making it easier to build full-stack, event-driven applications within FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;use-cases&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/#use-cases&quot;&gt;Use Cases&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse MQTT Service simplifies access to real-time data, an important element in optimizing industrial processes. With the power of FlowFuse, Node-RED and the MQTT service, your integrations are now even easier. Here are some typical uses cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connect your MQTT enabled PLCs (like Omron N Series, Siemens S7, etc) to your Node-RED instance to open up such possibilities like:
&lt;ul&gt;
&lt;li&gt;Data collection and analysis, Predictive Maintenance, OEE, Condition Based Monitoring.&lt;/li&gt;
&lt;li&gt;Triggering actions like sending Emails or alerting your engineers about an event.&lt;/li&gt;
&lt;li&gt;Realtime production monitoring of your facility.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Make use of modern IIoT devices on legacy systems by bridging the gap with MQTT.&lt;/li&gt;
&lt;li&gt;Connect disparate systems together where Node-RED and FlowFuse act as the central hub for data processing and routing. This gives you the advantage of transforming data on the fly, applying extra contextual data from other systems, apply routing rules, and much more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pricing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/#pricing&quot;&gt;Pricing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re on the Pro or Enterprise tiers of FlowFuse Cloud, then you don&#39;t have to pay any extra to get started with the MQTT Service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pro Tier:&lt;/strong&gt; Includes &lt;strong&gt;5 clients for free&lt;/strong&gt; as part of your existing plan&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise Tier:&lt;/strong&gt; Includes &lt;strong&gt;20 clients for free&lt;/strong&gt; as part of your existing plan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the near future we&#39;ll be publishing extra packages of clients that you can add to your team, beyond the amounts included with the base tiers.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To get started with your own MQTT Clients, navigate to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, and Sign In.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the new &amp;quot;Broker&amp;quot; option in the left navigation menu&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Create Client&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of FlowFuse&#39;s &amp;quot;Create Client&amp;quot; interface&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-add-client.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of FlowFuse&#39;s &amp;quot;Create Client&amp;quot; interface&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Fill out the client&#39;s credentials (Username + Password)&lt;/li&gt;
&lt;li&gt;Define the &amp;quot;Access Control Rules&amp;quot; (see more below)&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Confirm&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With your client created, you can then, in Node-RED, use the MQTT nodes to connect to your new client.&lt;/p&gt;
&lt;p&gt;Setting up a new broker in Node-RED, you can use your credentials accordingly:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img width=&quot;400&quot; data-zoomable=&quot;&quot; alt=&quot;Screenshot of the MQTT Config, &amp;quot;Connection&amp;quot; tab in the Node-RED Editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-config.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the MQTT Config, &amp;quot;Connection&amp;quot; tab in the Node-RED Editor&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And the respective &amp;quot;Security&amp;quot; tab:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img width=&quot;440&quot; data-zoomable=&quot;&quot; alt=&quot;Screenshot of the MQTT Config, &amp;quot;Security&amp;quot; tab in the Node-RED Editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-security.png&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the MQTT Config, &amp;quot;Security&amp;quot; tab in the Node-RED Editor&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;access-control-rules&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/#access-control-rules&quot;&gt;Access Control Rules&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In MQTT, you can publish and subscribe to &lt;em&gt;topics&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;These topics are strings that you can use to organise your data. In the Access Control Rules, you can define which topics your client can publish and subscribe to.&lt;/p&gt;
&lt;p&gt;For example, in a flow deployed to many PLCs on your factory floor, you might be publishing to the topics &lt;code&gt;factory/body-shop/plc/1&lt;/code&gt;, &lt;code&gt;factory/body-shop/plc/2&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Simplified example of MQTT data flow for a Factory Floor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-factory-architecture.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Simplified example of MQTT data flow for a Factory Floor&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Then, in a Cloud-Hosted flow, you can subscribe to &lt;code&gt;factory/body-shop/plc/#&lt;/code&gt; to receive all messages from all PLCs in the body shop, and display relevant data into a Dashboard.&lt;/p&gt;
&lt;p&gt;Each client that you create can be constrained in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt;: You can limit clients to whether than can &lt;em&gt;only&lt;/em&gt; subscribe, &lt;em&gt;only&lt;/em&gt; publish, or conduct both actions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;: You can control which topics a given client can interact with.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These constraints are particularly useful to ensure security throughout your MQTT network, and to ensure that data is only being sent and received by the correct components.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/</id>
        <title>FlowFuse 2.10: MQTT Broker, Improved Version Control &amp; More!</title>
        <summary>Let&#39;s take a look at the new features and improvements in FlowFuse 2.9</summary>
        <updated>2024-10-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;With FlowFuse 2.10 we&#39;ve added some new major features, as well as improvements across the board for FlowFuse users.&lt;/p&gt;
&lt;p&gt;Most notably, FlowFuse now offers it&#39;s own MQTT service, with the option to create MQTT client credentials for your teams, making it even easier and quicker to build your full-stack Node-RED applications.&lt;/p&gt;
&lt;h2 id=&quot;mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#mqtt-broker&quot;&gt;MQTT Broker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is a significant milestone for FlowFuse, as we&#39;re now offering our own MQTT service. We have listened to a lot of feedback from users and prospective customers, and this has consistently been a regularly requested offering, and so we are delighted to announce that this is now live on FlowFuse Cloud for our Enterprise teams.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the UI to manage your MQTT clients&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-mqtt-client-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This feature allows you to run and manage your own MQTT Clients alongside your Node-RED instances, making it easier to build full-stack applications within FlowFuse.&lt;/p&gt;
&lt;h3 id=&quot;pricing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#pricing&quot;&gt;Pricing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From today, Enterprise teams on FlowFuse Cloud will be able to create up to 20 clients on their accounts at &lt;strong&gt;no extra cost&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In the near future, users will then be able to purchase additional packs of clients to add to their team.&lt;/p&gt;
&lt;p&gt;Self-hosted Enterprise customers will be able to make use of this feature in our next release.&lt;/p&gt;
&lt;h2 id=&quot;version-history---visual-timeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#version-history---visual-timeline&quot;&gt;Version History - Visual Timeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since early iterations of FlowFuse, Snapshots have played a key role in Version Control for your Node-RED flows, environment variables and settings. Whilst we still offer the same &amp;quot;Snapshots&amp;quot; view in the application, we&#39;ve also added a new view to give a clearer picture of what flows are running on your Node-RED instances and &lt;em&gt;when&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing an Instance&#39;s visual timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-visual-timeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In this view, you can see every time a new set of flows were deployed to your Node-RED instance, no matter the source, whether that&#39;s from the Editor itself, via our &lt;a href=&quot;https://flowfuse.com/docs/user/devops-pipelines/&quot;&gt;DevOps Pipelines&lt;/a&gt;, or restoring a Snapshot.&lt;/p&gt;
&lt;h2 id=&quot;device-group-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#device-group-environment-variables&quot;&gt;Device Group Environment Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve also added in the ability to define common environment variables in your Device Groups.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Device Group Environment Variables&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-group--with-env-vars.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;These will now be deployed to any devices contained within a given group, and can still be overridden by environment variables defined in the Device&#39;s settings directly.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://flowfuse.com/docs/user/device-groups/&quot;&gt;Device Group documentation&lt;/a&gt; for more information on how to set environment variables for your device groups.&lt;/p&gt;
&lt;h2 id=&quot;and-much-more...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#and-much-more...&quot;&gt;And Much More...&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.10 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.10.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.10, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have an Enterprise license please make sure to review this &lt;a href=&quot;https://flowfuse.com/changelog/2024/08/enterprise-license-update/&quot;&gt;changelog entry&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/flowfuse-release-2-10/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/</id>
        <title>FlowFuse Security Features You Didn’t Know You Needed</title>
        <summary>Powerful Security Features That Enhance Your Node-RED applications</summary>
        <updated>2024-10-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;When it comes to securing Node-RED applications and its editor, ensuring that your flows and data are protected from unauthorized access can feel like a daunting task. Even after investing considerable time, achieving the right level of security often remains a complex challenge. For enterprises, this goes far beyond access control— security is a cornerstone of protecting sensitive data, maintaining operational continuity, and meeting strict regulatory requirements. A robust security framework not only prevents breaches but also safeguards intellectual property, preserves trust, and shields the organization from costly cyber threats.&lt;/p&gt;
&lt;p&gt;Here are 9 ways FlowFuse simplifies and strengthens your Node-RED deployments, ensuring you’re fully protected without the hassle.&lt;/p&gt;
&lt;h2 id=&quot;default-security-measures-to-keep-your-environment-safe&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#default-security-measures-to-keep-your-environment-safe&quot;&gt;Default Security Measures to Keep Your Environment Safe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Securing your Node-RED applications is essential to protect sensitive data, proprietary business logic, and critical systems from unauthorized access or cyberattacks. Without proper safeguards, the risks of data loss, operational disruptions, and reputational damage are significant. FlowFuse implements robust security measures right from the start, ensuring your deployments remain safe. Data is encrypted during transmission, and rate limiting prevents traffic overloads, ensuring smooth operations. Additionally, secure tunnelling facilitates safe communication between your edge devices and the FlowFuse platform. To ensure that only authorized personnel have access to your FlowFuse team, we’ve implemented strong login authentication measures, which can be further enhanced with multi-factor authentication as needed.&lt;/p&gt;
&lt;p&gt;Here’s the best part- we don’t just offer default protections; we empower you to fine-tune your security defences. FlowFuse features a user-friendly interface that allows you to customize your security settings and design a strategy tailored to your needs. Rest easy knowing that we&#39;ve laid a solid security foundation while giving you the flexibility to enhance your defences.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in learning more about how we safeguard your data privacy and security, we invite you to read our detailed &lt;a href=&quot;https://flowfuse.com/platform/security/&quot;&gt;security statement&lt;/a&gt;. Additionally, we are proud to announce that &lt;a href=&quot;https://flowfuse.com/blog/2024/01/soc2/&quot;&gt;FlowFuse has achieved SOC 2 Type 1 compliance&lt;/a&gt;, demonstrating our commitment to maintaining the highest standards in security and data protection.&lt;/p&gt;
&lt;h3 id=&quot;single-sign-on-(sso)-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#single-sign-on-(sso)-integration&quot;&gt;Single Sign-On (SSO) Integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every organization relies on various tools and platforms to enhance productivity and efficiency. Providing seamless access to these resources is vital for optimizing workflows. That’s where Single Sign-On (SSO) comes in, it simplifies the onboarding and offboarding processes.&lt;/p&gt;
&lt;p&gt;With SSO, team members can log in using their existing credentials, eliminating the hassle of remembering multiple passwords. This streamlines their login experience and enables them to be productive from day one.&lt;/p&gt;
&lt;p&gt;To implement SSO for your self-hosted FlowFuse, refer to the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/&quot;&gt;How to Set Up SSO SAML for Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/&quot;&gt;How to Set Up SSO LDAP for Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using FlowFuse Cloud, please get in touch with us for configuration assistance.&lt;/p&gt;
&lt;h3 id=&quot;two-factor-authentication-(2fa)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#two-factor-authentication-(2fa)&quot;&gt;Two-Factor Authentication (2FA)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ve all been there, managing countless passwords, hoping they&#39;re strong enough to protect against security threats. But in today’s digital world, passwords alone aren’t sufficient. That’s why Two-Factor Authentication (2FA) has become essential.&lt;/p&gt;
&lt;p&gt;FlowFuse understands this need. By enabling 2FA, even if someone gets hold of your password, they&#39;ll still require a second form of verification—like a code sent to your phone—to access your account. This simple yet powerful layer of security ensures your data is much safer from unauthorized access. However, when Single Sign-On (SSO) is enabled, 2FA will be replaced by SSO&#39;s authentication process.&lt;/p&gt;
&lt;p&gt;To set up 2FA in FlowFuse, you’ll need to head over to &lt;strong&gt;User Settings &amp;gt; Security &amp;gt; Two-Factor Authentication&lt;/strong&gt;. It’s as simple as clicking the &amp;quot;Enable Two-Factor Authentication&amp;quot; button, scanning the QR code displayed on the platform with your authenticator app, and then entering the code from your app back into FlowFuse. Once you&#39;ve done that, 2FA will be up and running, adding that extra layer of security to your account!&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Two-Factor Authentication&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/2f-auth.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Two Factor Authentication&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;granular-role-based-access-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#granular-role-based-access-management&quot;&gt;Granular Role-Based Access Management&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With collaboration at its core, FlowFuse allows you to create teams and invite members to collaborate on projects. However, not all team members require access to every feature. Effective management is essential, as some members might feel overwhelmed by unnecessary options, and there&#39;s a risk of accidental changes being made by those who are unfamiliar with the configurations and settings.&lt;/p&gt;
&lt;p&gt;To address this, FlowFuse offers &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;Role-Based Access Control (RBAC)&lt;/a&gt;. When inviting team members, you can assign specific roles that provide the appropriate level of access for their work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Owner&lt;/strong&gt;: Has full control over the team settings, applications, instances, and flows. Can invite users and change their roles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Member&lt;/strong&gt;: Can access applications and instances and modify flows, but with limited permissions compared to the Owner. Cannot manage team, application, or instance settings or invite users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Viewer&lt;/strong&gt;: Can view instances and flows but cannot make any changes. Ideal for users who need to monitor without editing capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard Only&lt;/strong&gt;: Restricted to accessing the dashboard or HTTP endpoint. This role is for users who only need to monitor status without making any changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Role Base Accesss control&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/rbac.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Role Base Accesss control&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Additionally, you can later change the roles of team members in the &amp;quot;members&amp;quot; page. This helps prevent unauthorized changes and ensures a more secure and efficient workflow.&lt;/p&gt;
&lt;h3 id=&quot;comprehensive-activity-audit-logs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#comprehensive-activity-audit-logs&quot;&gt;Comprehensive Activity Audit Logs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today, many organizations prioritize a culture of openness and transparency, but security remains a top concern. Our &lt;strong&gt;Audit Logs&lt;/strong&gt; feature supports this dual focus by maintaining a comprehensive record of all actions in the platform. These logs detail who made changes, what was changed, and when it occurred, ensuring accountability and enabling teams to quickly identify any unauthorized access or mistakes that could jeopardize security.&lt;/p&gt;
&lt;p&gt;We provide audit logs at three different levels: &lt;strong&gt;instance level&lt;/strong&gt;, where all action logs related to a specific instance are recorded; &lt;strong&gt;application level&lt;/strong&gt;, which groups logs from instances created within a particular application; and &lt;strong&gt;team level&lt;/strong&gt;, where all platform activities are documented but visible only to admins. This layered approach helps organizations maintain secure workflows and demonstrates their commitment to transparency, ensuring that security concerns are effectively addressed without sacrificing openness.&lt;/p&gt;
&lt;p&gt;To access the audit logs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;instance-level logs&lt;/strong&gt;, choose the specific instance you want to see and go to &lt;strong&gt;Audit Logs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Instance-level Audit Logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/instance-audit-logs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse: Instance-level Audit Logs&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;application-level logs&lt;/strong&gt;, select the application you want to view and navigate to &lt;strong&gt;Audit Logs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Application-level Audit Logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/application-audit-logs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Application-level Audit Logs&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;team-level logs&lt;/strong&gt;, there will be an option labeled &lt;strong&gt;&amp;quot;Audit Logs&amp;quot;&lt;/strong&gt; in the left sidebar, accessible only to admins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Team-level Audit Logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/team-audit-logs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Team-level Audit Logs&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For more information refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/logs/#audit-log&quot;&gt;Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;instance-protection-mode&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#instance-protection-mode&quot;&gt;Instance Protection Mode&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Imagine your Node-RED application running smoothly on the production line, seamlessly handling critical tasks and data flows. Now, picture the chaos that could ensue if someone from your team accidentally modified a flow. While we offer the &lt;a href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/&quot;&gt;snapshot&lt;/a&gt; feature to recover previous changes, accidental modifications may not be identified quickly. Even when they are discovered, and the snapshot is used to restore the previous state, it can still take seconds or even minutes to recover, resulting in costly downtime.&lt;/p&gt;
&lt;p&gt;To prevent such scenarios, we provide a feature called &lt;strong&gt;Instance Protection Mode&lt;/strong&gt;. This mode allows you to set flows within your Node-RED instances to read-only, ensuring that modifications can only occur through a &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;DevOps pipeline&lt;/a&gt;. This process guarantees that even the most critical flows can only be altered with thorough testing and approval.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Option to Enable the Instance Protection Mode&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/instance-protection.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Option to Enable the Instance Protection Mode&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With Instance Protection Mode activated, team members can still view flows, but any attempts to modify them are blocked, providing an additional layer of security. This approach protects the integrity of your applications and fosters a controlled environment for making changes safely.&lt;/p&gt;
&lt;h3 id=&quot;secure-http-nodes-endpoints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#secure-http-nodes-endpoints&quot;&gt;Secure HTTP Nodes Endpoints&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;HTTP is one of the most widely used protocols for enabling communication between different applications and services. In Node-RED, you can quickly create these APIs using HTTP-In nodes, which allow for communication. However, while this convenience is excellent, ensuring that only authorized users can access your APIs is essential.&lt;/p&gt;
&lt;p&gt;FlowFuse provides robust options for securing all HTTP endpoints served by Flow and the Node-RED Dashboard. To manage this, each instance has a dedicated interface that you can access by navigating to &lt;strong&gt;your instance -&amp;gt; Settings -&amp;gt; Security&lt;/strong&gt;. Here, you’ll find several options for securing your APIs:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Options to enable authentication for the HTTP endpoints created in the Node-RED instance&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/http-api-auth.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Flowfuse: Options to enable authentication for the HTTP endpoints created in the Node-RED instance.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;None (Default)&lt;/strong&gt;: No authentication is enabled by default, which means anyone can access your endpoints.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Basic Authentication&lt;/strong&gt;: By selecting this option, two input fields will appear where you can enter a username and password. This ensures that only users with the correct credentials can access your APIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse User Authentication&lt;/strong&gt;: This option allows all team members to use their unique usernames and passwords when requesting API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bearer Tokens&lt;/strong&gt;: For more advanced users, there’s an option to generate bearer tokens for secure API access without needing to send usernames and passwords. With this feature, you can also set expiration times for these tokens, ensuring that access is time-limited and reducing the risk of unauthorized use. To use bearer tokens, you must first enable &lt;strong&gt;FlowFuse User Authentication&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/&quot;&gt;HTTP Authentication in Node-RED with FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With these features, FlowFuse gives you complete control over who can access your APIs created in the Node-RED instance.&lt;/p&gt;
&lt;h3 id=&quot;api-token-management-for-secure-platform-interactions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#api-token-management-for-secure-platform-interactions&quot;&gt;API Token Management for Secure Platform Interactions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We understand that organizations need to create integrations for automation, monitoring, and efficient workflows. FlowFuse provides REST APIs that allow easy interaction with various platform parts, including users, instances, teams, devices, and more. However, security settings are protected to ensure they can only be updated by admins or authorized team members directly on the platform, not via APIs.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Options to generate bearer tokens for secure API access&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/genrate-token-for-platform-api.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse: Interface for generating bearer tokens to ensure secure interactions with the platform APIs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Protecting against unauthorized access is crucial, especially since you control and monitor your entire factory and production lines through this platform. To safeguard this, we offer an interface similar to the one used for bearer tokens. You can access this by navigating to &lt;strong&gt;User Settings &amp;gt; Security &amp;gt; Tokens&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For more information, refer to the &lt;a href=&quot;https://flowfuse.com/docs/api/&quot;&gt;FlowFuse Platform API docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;software-bills-of-materials&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-security-features/#software-bills-of-materials&quot;&gt;Software Bills of Materials&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is an open-source platform maintained by dedicated community members who ensure it operates smoothly and remains free of security vulnerabilities. Similarly, there exists a vast ecosystem of open-source packages, nodes, and libraries that we frequently use in our projects. While these packages are often excellent and enhance our capabilities, some may need a regular team or individual to update and monitor them. This can lead to potential risks, as outdated or unmaintained packages can introduce vulnerabilities into our applications.&lt;/p&gt;
&lt;p&gt;To address these concerns, we recently introduced the Software Bill of Materials (SBOM) feature, which adds an extra layer of security and compliance. An SBOM is a detailed list of all an application&#39;s components. It provides a comprehensive view of all third-party libraries used in each application instance and their latest versions. This allows teams to monitor dependencies and make informed decisions about upgrades, ensuring effective dependency management and enhanced resilience against security threats.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Software Bills of Materials&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sbom.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;FlowFuse: Software Bills of Materials Inteface&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For more information, refer to the &lt;a href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/&quot;&gt;Article on FlowFuse Software Bills of Materials&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In conclusion, FlowFuse offers a comprehensive suite of security features designed to empower you with the tools to protect your Node-RED applications effectively. Understanding and utilizing these security features will help you maintain a secure and efficient environment for your Node-RED applications. With FlowFuse, you can confidently safeguard your deployments, ensuring robust protection against unauthorized access while enhancing collaboration within your team.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/</id>
        <title>Transform Chaos into Control: Centralize Node-RED Management with FlowFuse</title>
        <summary>With FlowFuse, you can simplify managing all your Node-RED Instances and remote IoT device management</summary>
        <updated>2024-10-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Managing a single Node-RED instance involves setting up and configuring a server, securely tunneling for remote access to edge devices, and ensuring proper networking and firewall configurations, all of which can be complex. The complexity increases when overseeing multiple Node-RED instances spread across various projects, edge devices, or environments.
This situation brings additional challenges that can make management a really difficult task, often leading to confusion and frustration as teams try to keep everything running smoothly, troubleshoot issues, and ensure clear communication between instances. Consolidating control into a single platform simplifies deployment, configuration, collaboration, and oversight, making it easier to manage multiple Node-RED instances. Let’s explore how FlowFuse can centralize this management.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-node-red-instance%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/#what-is-a-node-red-instance%3F&quot;&gt;What is a Node-RED Instance?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; instance refers to a single, operational setup of the Node-RED application. Whether you start Node-RED on your computer, a cloud server, or an edge device, you create an instance. Each instance operates independently, allowing you to build and run automation flows or applications.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-challenges-of-managing-multiple-node-red-instances%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/#what-are-the-challenges-of-managing-multiple-node-red-instances%3F&quot;&gt;What are the Challenges of Managing Multiple Node-RED Instances?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing multiple Node-RED instances can quickly become complicated as operations grow. Each new instance adds complexity, from configuration issues to security concerns. These challenges highlight the need for a centralized solution to simplify management and improve efficiency.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment and Configuration Management:&lt;/strong&gt; Setting up Node-RED instances on a server requires technical knowledge and ongoing maintenance. As the number of instances grows, maintaining them can become time-consuming and resource-intensive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Egde Node-RED Management:&lt;/strong&gt; Managing Node-RED instances on edge devices introduces additional challenges, such as the need for on-site troubleshooting when issues arise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring and Troubleshooting:&lt;/strong&gt; Keeping track of the health and performance of multiple instances requires constant attention. Checking logs across different instances can become overwhelming.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security Management:&lt;/strong&gt; Each instance requires its own security settings. Ensuring that all instances are secure and up to date can be a difficult task, especially as the number of instances increases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backup and Recovery:&lt;/strong&gt; Having a solid backup and recovery plan is critical. If a system crashes, you need a way to quickly restore it without losing important data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scaling:&lt;/strong&gt; As applications grow in complexity, scaling Node-RED instances becomes necessary. This requires expertise in server management and the ability to handle multiple instances efficiently.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ensuring High Availability:&lt;/strong&gt; In production environments, keeping all Node-RED instances running smoothly and avoiding downtime is essential which also requires high technical exepertise&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A centralized platform is essential to handle deployment, configuration, and management efficiently, providing a visual interface to maintain and update instances.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;As organizations navigate the complexities of the digital age, adopting a holistic approach that integrates technology, processes, and people is essential for reaping the full benefits of IoT.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;flowfuse%3A-centralize-your-node-red-and-iot-device-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/#flowfuse%3A-centralize-your-node-red-and-iot-device-management&quot;&gt;FlowFuse: Centralize Your Node-RED and IoT Device Management&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is a powerful platform designed to simplify the management of multiple Node-RED instances. By providing a centralized interface, FlowFuse enables users to manage, scale, secure, and collaborate on Node-RED solutions.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Centralized Node-RED Management&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/instances.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing how multiple Node-RED instances are organized and managed under one roof.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With FlowFuse, you can organize your Node-RED instances into teams for improved collaboration, allowing seamless teamwork on projects without the need to navigate between different instance locations physically. You can create as many teams as needed, ensuring that instances are organized based on the team members assigned to them. Additionally, you can ensure that each member has the correct permissions they require through role-based access control (RBAC), providing precise management of access and responsibilities.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Immersive Editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/imersive-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing how FlowFuse&#39;s immersive editor simplifies managing settings and configuration within the Node-RED editor.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse also simplifies the &lt;a href=&quot;https://flowfuse.com/solutions/edge-connectivity/&quot;&gt;monitoring and controlling of edge devices&lt;/a&gt; through the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt;, which quickly connects your devices to the cloud platform and allows you to build and monitor applications remotely.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Device Management&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devices.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing remote edge devices connected through the FlowFuse platform for remote monitoring and control.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Additionally, FlowFuse enables the creation of &lt;a href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/&quot;&gt;DevOps pipelines&lt;/a&gt; that ensure your application is well-tested and evaluated before deployment to production. Deploying the same flow to hundreds or thousands of devices becomes effortless with these pipelines.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Devops Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devops.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing feature to create the devops pipeline for Node-RED instances&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can efficiently &lt;a href=&quot;https://flowfuse.com/docs/user/logs/#logs&quot;&gt;monitor logs&lt;/a&gt; for each instance and receive instant email alerts if any crashes occur, facilitating quick troubleshooting.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/log.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the Node-RED instance logs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse also allows you to quickly add &lt;a href=&quot;https://flowfuse.com/docs/user/high-availability/&quot;&gt;high availability&lt;/a&gt; features to your instances, ensuring smooth and efficient operation of your production applications. The platform includes an auto-snapshot feature that lets you recover from accidental changes to flows, ensuring you always have a backup of your application.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;High availability&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/high-availablity.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing the feature that allows to enable high availability for instances&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Snapshots&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshots.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Image showing snapshots feature&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We have highlighted just a few features of FlowFuse; there are many more—potentially three to four times what has been presented—and the team is continuously working to develop and introduce new functionalities to improve collaboration, scalability, security, and overall performance.&lt;/p&gt;
&lt;h3 id=&quot;how-flowfuse-transforms-production-operations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/#how-flowfuse-transforms-production-operations&quot;&gt;How FlowFuse Transforms Production Operations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In manufacturing, downtime is costly, and managing machines, sensors, and systems across multiple sites can be complex. FlowFuse simplifies this by centralizing management, giving you a single platform to oversee all your Node-RED instances efficiently.&lt;/p&gt;
&lt;p&gt;With its intuitive interface, FlowFuse handles deployments, updates, and real-time monitoring, ensuring smooth production. It collects data from hardware, APIs, and services using a drag-and-drop interface, enabling teams to easily connect, transform, and analyze data. The high-availability feature ensures critical operations continue even during failures, minimizing downtime.&lt;/p&gt;
&lt;p&gt;FlowFuse also enhances security with advanced settings, keeping your systems safe while boosting collaboration. As operations grow, FlowFuse scales seamlessly, integrating new devices and systems without added complexity.&lt;/p&gt;
&lt;p&gt;By simplifying system management, FlowFuse cuts costs, keeps production running smoothly, and lets your team focus on growth and innovation.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/managing-node-red-instances-in-centralize-platfrom/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse transforms how you manage Node-RED instances, turning chaos into clarity. With centralized control, teams can collaborate and reduce operational costs while ensuring critical applications remain available and secure. Automated backups and high availability translate to less downtime and more focus on innovation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/</id>
        <title>FlowFuse&#39;s Software bills of material helps enhance Application Security and Management</title>
        <summary>Enhancing the Security and Compliance of Your Solutions</summary>
        <updated>2024-10-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;FlowFuse recently launched Software Bill of Materials (SBoM) for enterprise customers. This powerful tool enhances security and management within projects, particularly in the Node-RED ecosystem. As open-source libraries and software continue to play a pivotal role in the industry, monitoring third-party components used in projects becomes essential. The SBoM enables organizations to track dependencies and identify vulnerabilities, ensuring compliance and mitigating risks.&lt;/p&gt;
&lt;h2 id=&quot;what-is-an-sbom%2C-and-how-does-it-enhance-security%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/#what-is-an-sbom%2C-and-how-does-it-enhance-security%3F&quot;&gt;What is an SBoM, and How Does It Enhance Security?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Software Bill of Materials (SBoM) is a detailed list of all the components that make up a software application. Just as a bill of materials for a physical product lists every part used in its construction, an SBoM provides a breakdown of all the software libraries, packages, and dependencies in a project.&lt;/p&gt;
&lt;p&gt;This transparency is crucial for security, allowing developers and organizations to track what’s inside their software. By knowing precisely what components are in use, you can quickly identify outdated or vulnerable dependencies that may pose security risks. An SBoM helps you monitor third-party nodes, ensuring that any related security issues can be addressed promptly and reducing the chance of vulnerabilities being exploited.&lt;/p&gt;
&lt;h2 id=&quot;how-you-can-use-sbom-to-enhance-security-in-your-node-red-applications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/#how-you-can-use-sbom-to-enhance-security-in-your-node-red-applications&quot;&gt;How You Can Use SBoM to Enhance Security in Your Node-RED Applications&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are some effective strategies for leveraging SBoM in your Node-RED applications:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Regular Monitoring&lt;/strong&gt;: Frequently review your SBoM to identify outdated or vulnerable packages. Proactive monitoring helps catch potential security threats early.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Timely Upgrades&lt;/strong&gt;: When you spot vulnerabilities in your packages, prioritize upgrading them. Keeping dependencies up to date is crucial for maintaining security and performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Evaluate Third-Party Nodes&lt;/strong&gt;: Assess the third-party nodes in your application. If any appear unmaintained or outdated, consider alternatives to ensure ongoing security.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By integrating these practices into your workflow, you can effectively manage dependencies and strengthen the security of your Node-RED solutions.&lt;/p&gt;
&lt;h2 id=&quot;exploring-the-flowfuse-sbom-feature&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/#exploring-the-flowfuse-sbom-feature&quot;&gt;Exploring the FlowFuse SBoM Feature&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To support the effective monitoring and assessment of your dependencies, FlowFuse provides a dedicated Software Bill of Materials (SBoM) interface in the platform. For those who may not be familiar, &lt;strong&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;&lt;/strong&gt; offers a comprehensive platform that enables engineers to effectively build, manage, and secure their applications. By integrating IT and operational technology (OT) environments, FlowFuse streamlines the process of connecting, collecting, transforming, and visualizing industrial data.&lt;/p&gt;
&lt;h3 id=&quot;accessing-flowfuse-sbom-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/#accessing-flowfuse-sbom-interface&quot;&gt;Accessing FlowFuse SBoM Interface&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Software Bill of Materials (SBoM) interface is available at the application level. For more information on the application, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#application&quot;&gt;Documentation&lt;/a&gt;. To access it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your Node-RED application within the FlowFuse platform.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Applications&#39; option in the FlowFuse platform&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/applications-options-in-the-ff.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Applications&#39; option in the FlowFuse platform.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Click the &lt;strong&gt;Dependencies&lt;/strong&gt; option at the top to switch to the SBoM interface.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Dependencies&#39; option in the FlowFuse platform for the SBoM interface.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dependencies-tab-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Dependencies&#39; option in the FlowFuse platform for the SBoM interface.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This feature is only available for FlowFuse Enterprise customers.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;understanding-what-the-sbom-interface-shows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-sbom-feature/#understanding-what-the-sbom-interface-shows&quot;&gt;Understanding What the SBoM Interface Shows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you navigate the tab, you will see a list of all the packages installed within your Node-RED Cloud instances and devices associated with that application. This includes the package names and versions, the number of devices and instances using each version, and additional details such as the latest available version of each package and the time since its release.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the Dependencies tab along with the detailed notes of each item displayed.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/the-dependency-tab-info.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the Dependencies tab along with the detailed notes of each item displayed.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Incorporating a Software Bill of Materials into your development process not only enhances security but also fosters a culture of accountability and transparency within your team. By understanding your dependencies, you can make informed decisions that protect your applications and ensure compliance with industry standards.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/</id>
        <title>Dialogs, Customizable Icons and Histograms Now Available in FlowFuse Dashboard</title>
        <summary>Our latest update for FlowFuse Dashboard introduces a new group type, Dialog, a new chart variation, Histogram and customization support for the application icon.</summary>
        <updated>2024-10-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This update introduces new ways to enhance data visualization and customization in your dashboards. With key improvements, including a new chart type, customizable app icon support and a dialog feature for groups, this release helps tailor dashboards for better user interaction and flexibility.&lt;/p&gt;
&lt;h2 id=&quot;new-chart-type%3A-histogram&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/#new-chart-type%3A-histogram&quot;&gt;New Chart Type: Histogram&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Histograms are an essential tool for data analysis, offering a clear way to visualize distributions. The latest Dashboard update introduces a fully customizable histogram chart type, allowing you to present frequency distributions for your data.&lt;/p&gt;
&lt;p&gt;Whether analyzing performance metrics or user activity, histograms can give you a clear view of how data points are distributed across predefined ranges. You can now easily group data and control the range, providing deeper insights at a glance.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Histogram chart type&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/chart-histogram.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new Histogram chart type&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The real advantage of this new Histogram chart type is that it simplifies the process for you. Just pass in the raw data, and the histogram will automatically organize it into meaningful ranges, then display how often each range occurs. This makes it incredibly easy to extract valuable insights without the need for manual data processing.&lt;/p&gt;
&lt;p&gt;You can see an example flow for the Histogram chart type &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-chart.html#histograms&quot;&gt;here&lt;/a&gt; in our documentation.&lt;/p&gt;
&lt;h2 id=&quot;customizable-app-icon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/#customizable-app-icon&quot;&gt;Customizable App Icon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Branding is an essential part of any user experience and with this new feature, you can customize your dashboard&#39;s app icon. The Node-RED Dashboard 2.0 now allows users to provide their own application icon, which appears in the browser tab and when the dashboard is installed as a Progressive Web App (PWA). This customization helps reinforce your brand, whether you’re developing IoT solutions, monitoring systems or creating dashboards for end-users.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img style=&quot;max-width: 400px; margin: auto;&quot; data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the customizable app icon in browser and as a PWA&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/app-icon-installation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the customizable app icon in browser and as a PWA&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can configure the icon by navigating to the base UI settings (ui-base) and providing an icon URL.&lt;/p&gt;
&lt;p&gt;You can read more about how to use this feature in the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/config/ui-base.html#application-icon&quot;&gt;App Icon Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-dialogs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/#building-dialogs&quot;&gt;Building Dialogs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Organizing data on dashboards has become more efficient with the new &amp;quot;Dialog/Modal&amp;quot; feature. Groups in Dashboard now have a new &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/config/ui-group.html#type&quot;&gt;&amp;quot;Type&amp;quot;&lt;/a&gt; property, so they can be rendered inline as before, or instead rendered as a Dialog. The display of the dialog groups can be controlled (opened/closed) via the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-control.html#show-hide&quot;&gt;Control&lt;/a&gt; node.&lt;/p&gt;
&lt;p&gt;This removes the need for building custom modals and dialogs in a Template node, and makes the entire experience of building your dialogs low-code.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing groups rendered as dialogs in the dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-group-type-dialog.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing groups rendered as dialogs in the dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;By utilizing groups as dialogs, users can maintain a clean dashboard while still having quick access to detailed data when required.&lt;/p&gt;
&lt;p&gt;You can read more about the new property, and see an example flow in the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/config/ui-group.html#type&quot;&gt;UI Group Documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can find the full 1.18.0 Release Notes &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v1.18.0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just to highlight a few, particularly valuable, updates and fixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Chart - Group tooltips for line chart.&lt;/li&gt;
&lt;li&gt;UI Button Group
&lt;ul&gt;
&lt;li&gt;Show node status&lt;/li&gt;
&lt;li&gt;Add pointerdown/pointerup event handling and fix button theming bug&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI Table - Support key type option for entering fixed strings as item labels&lt;/li&gt;
&lt;li&gt;UI Switch - Layout Switching with Dynamic Configuration Support&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/dashboard-new-group-type-app-icon-and-charts/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Work has already begun on the next release, &lt;code&gt;1.19.0&lt;/code&gt;, you can see what items we have queued up &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;here&lt;/a&gt;, if you&#39;ve got any feedback or suggestions, please do let us know, and feel free to open new issues on our &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/</id>
        <title>Exploring Quick Ways to Write Complex Logic in Function Nodes in Node-RED</title>
        <summary>Enhancing Your Node-RED Experience</summary>
        <updated>2024-10-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Node-RED is a powerful tool for building automation flows through its visual interface and low-code nodes. However, there are times when this low-code approach falls short, particularly when you need to implement complex JavaScript logic. That’s where the Function Node comes into play. Many Node-RED developers excel in their domains—such as IoT integration and PLCs—but may lack a strong foundation in JavaScript.
In this guide, I will share strategies for making writing in Function Nodes straightforward and efficient. You’ll learn how to leverage JavaScript&#39;s capabilities without needing extensive knowledge, empowering you to handle more complex logic with confidence and ease.&lt;/p&gt;
&lt;h2 id=&quot;what-are-function-nodes-and-the-challenges-related-to-them%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#what-are-function-nodes-and-the-challenges-related-to-them%3F&quot;&gt;What are function nodes and the challenges related to them?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node_function.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the function node&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-are-function-nodes-and-common-challenges%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#what-are-function-nodes-and-common-challenges%3F&quot;&gt;What Are Function Nodes and Common Challenges?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/function/&quot;&gt;Function Nodes&lt;/a&gt; in Node-RED allow you to write custom JavaScript for processing messages. While they provide flexibility, many users find it challenging to turn complex business rules into code and manage variables. For more details on the benefits and drawbacks of using Function Nodes, refer to this &lt;a href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/&quot;&gt;Article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before using Function Nodes, consider if existing low-code nodes can fulfill your needs. Using standard low-code nodes can simplify your approach and enhance collaboration and clarity. If you still feel the need to use Function Nodes, don’t worry, In the following section, we’ll explore straightforward strategies to make working with Function Nodes easier.&lt;/p&gt;
&lt;h2 id=&quot;quick-ways-to-simplify-writing-in-function-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#quick-ways-to-simplify-writing-in-function-nodes&quot;&gt;Quick Ways to Simplify Writing in Function Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;using-blockly-based-function-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#using-blockly-based-function-nodes&quot;&gt;Using Blockly-Based Function Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For users seeking to simplify the process of writing complex logic, Blockly-based Function Nodes serve as a valuable tool within Node-RED. Designed to facilitate JavaScript code generation, Blockly allows you to construct logic visually using a drag-and-drop interface with pre-defined blocks. This makes it easier to translate intricate business rules into functional code. As you build your logic, Blockly automatically generates the corresponding JavaScript.&lt;/p&gt;
&lt;p&gt;Before proceeding, make sure you have installed the following Node-RED package via the palette manager:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-blockly&lt;/strong&gt;: This package adds the Blockly custom node in your Node-RED sidebar to use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the demonstration, let&#39;s consider we have an array of temperatures, and we wanted to calculate the Upper Control Limit (UCL) and Lower Control Limit (LCL) to send to different outputs.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Blockly node onto the canvas and double-click it to open the editor.&lt;/li&gt;
&lt;li&gt;Once open, you will see the block categories on the left side, a plain canvas on the right side, and an option to set output and timeout at the bottom. Set the output to 2.&lt;/li&gt;
&lt;li&gt;In the left sidebar, you’ll find different categories starting with Node-RED, each containing related operation blocks. For example, in Node-RED, you’ll find blocks to get the value of &lt;code&gt;msg.payload&lt;/code&gt;, set &lt;code&gt;msg.payload&lt;/code&gt;, and more. In the Math category, there are various blocks for different mathematical operations.&lt;/li&gt;
&lt;li&gt;We must first calculate the mean to calculate UCL and LCL. Switch to the Math category and drag the block labeled &amp;quot;&lt;code&gt;sum&lt;/code&gt; of the list.&amp;quot; Click on the sum in the block to see other options; select &amp;quot;average&amp;quot; from it. Then, in the Node-RED category, find the block labeled &amp;quot;get the &lt;code&gt;msg&lt;/code&gt; property from &lt;code&gt;payload&lt;/code&gt;&amp;quot; and connect it to the end of the &amp;quot;&lt;code&gt;sum&lt;/code&gt; of the list&amp;quot; block. Now, to create a variable to store the mean, switch to the Variables category, click &amp;quot;create variable,&amp;quot; and name it &lt;code&gt;mean&lt;/code&gt;. Once you make the variable, you’ll get different blocks related to its perform operations on that var, such as setting and changing its value. Drag the block labeled &amp;quot;set to mean&amp;quot; and place it at the start of the &amp;quot;&lt;code&gt;average&lt;/code&gt; of list&amp;quot; block.&lt;/li&gt;
&lt;li&gt;Next, we know the formulas to calculate UCL and LCL (where we pick z = 3):&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;UCL = mean + (stdDev * z)&lt;/li&gt;
&lt;li&gt;LCL = mean - (stdDev * z)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;To calculate the standard deviation, switch to the Math category and drag the &amp;quot;&lt;code&gt;sum&lt;/code&gt; of the list&amp;quot; block again. Click on the sum and select the &amp;quot;standard deviation&amp;quot; option. Again, drag the block &amp;quot;get the &lt;code&gt;msg&lt;/code&gt; property from &lt;code&gt;payload&lt;/code&gt;&amp;quot; and connect it to the end of the standard deviation block. Create a variable called &lt;code&gt;stdDev,&lt;/code&gt; drag the &amp;quot;set stdDev to&amp;quot; block, and place it at the start of the &amp;quot;&lt;code&gt;standard deviation&lt;/code&gt; of the list&amp;quot; block.&lt;/li&gt;
&lt;li&gt;Now, it’s time to calculate UCL and LCL. First, create a variable for UCL and then Drag the &amp;quot;set UCL to&amp;quot; block, then switch to the Math category and drag the &amp;quot;1 + 1&amp;quot; block. Place the &lt;code&gt;mean&lt;/code&gt; variable in one of the positions for &amp;quot;1.&amp;quot; Drag the same block again and place it in the second position of 1, then switch to Variables again and drag the &lt;code&gt;stdDev&lt;/code&gt; variable to replace one of the &amp;quot;1s&amp;quot; in the second 1+1 block, and set the second &amp;quot;1&amp;quot; to 3.&lt;/li&gt;
&lt;li&gt;Next, switch to Node-RED and drag the &amp;quot;set &lt;code&gt;msg&lt;/code&gt; property &lt;code&gt;payload&lt;/code&gt; to&amp;quot; block. Then, drag the UCL from the variable and place it in place of &amp;quot;to.&amp;quot; s value, Drag the &amp;quot;send &amp;quot;&lt;code&gt;msg&lt;/code&gt; block to output 1&amp;quot;. Repeat the same steps for LCL, but make sure that you subtract from the mean (&lt;code&gt;stdDev * z&lt;/code&gt;) and set LCL to the payload, returning it to output 2.&lt;/li&gt;
&lt;li&gt;Finally, click Done to save it.&lt;/li&gt;
&lt;li&gt;Drag the inject node, having set the payload to an array of simulated temperature data, and connect its output to the input of the blockly node,&lt;/li&gt;
&lt;li&gt;Then, drag the two debug nodes onto the canvas. Connect one debug node to output 1 of the Blockly node (this will display the UCL) and the other debug node to output 2 (this will display the LCL).&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject button. You will see both UCL and LCL printed on the debug panel&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The final blockly canvas should look like the below image:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing collection of blockly blocks that are calculating UCL and LCL&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/blockly.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing collection of blockly blocks that are calculating UCL and LCL&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Using Blockly-based Function Nodes simplifies the creation of complex logic in Node-RED. However, a basic understanding of JavaScript is still beneficial, especially as your logic becomes more complicated. While beginners may appreciate the visual interface initially, it can become confusing when trying to implement more advanced features. Additionally, the Blockly Function Node is a modified version of the original Function Node, which may lead to differences in behavior and functionality. Nevertheless, it remains a valuable node for users looking to simplify writing function logics in Node-RED.&lt;/p&gt;
&lt;h3 id=&quot;using-flowfuse-expert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#using-flowfuse-expert&quot;&gt;Using FlowFuse Expert&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the quick function node generation with FlowFuse Expert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-ai-assistant.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the quick function node generation with FlowFuse Expert&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The FlowFuse Expert is an AI-based plugin integrated into the FlowFuse platform within the Node-RED editor, making it incredibly easy to generate complex functions using prompts.&lt;/p&gt;
&lt;p&gt;For this example, let’s use the same logic we demonstrated with Blockly:&lt;/p&gt;
&lt;p&gt;Before proceeding, ensure you have updated Node-RED to the latest version on the FlowFuse platform.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED instance editor on the platform.&lt;/li&gt;
&lt;li&gt;Click the magic button in the top right corner.&lt;/li&gt;
&lt;li&gt;A popup prompt will appear, asking for your input to generate the function node.&lt;/li&gt;
&lt;li&gt;Enter the prompt for your logic. For this example, you can use:
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Generate JavaScript code that takes an array of numbers, calculates the Upper Control Limit (UCL) and Lower Control Limit (LCL), then sends UCL to the first output of the function node and LCL to the second output.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Generate.&amp;quot; After 2-3 seconds, the Function Node with the requested JavaScript code will appear directly on your canvas.&lt;/li&gt;
&lt;li&gt;To test it, connect an inject node containing an array of simulated temperature data, then drag two debug nodes onto the canvas. Connect one debug node to output 1 of the function node (this will display the UCL) and the other debug node to output 2 (this will display the LCL).&lt;/li&gt;
&lt;li&gt;Deploy the flow and click the inject button; both UCL and LCL will be displayed on the debug panel.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using the FlowFuse Expert is significantly easier than Blockly, as it streamlines the process and saves you valuable time. You can articulate your goals in plain English or other languages, such as Spanish or Dutch, and the assistant generates your Function Node seamlessly. This allows you to focus more on your project objectives rather than getting bogged down in coding or block arrangements. Additionally, it provides you with the original Function Node, maintaining standard functionality.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/quick-ways-to-write-functions-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In summary, both Blockly and FlowFuse Expert simplify writing complex logic in Node-RED, but FlowFuse is easier to use. Blockly’s visual approach can be confusing, while FlowFuse allows you to generate code by stating your goals in plain English or other languages. Although Blockly can be helpful, it often requires JavaScript knowledge. FlowFuse Expert simplifies the process, allowing you to focus on your project.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/</id>
        <title>Using FlowFuse Project Nodes for Faster and More Efficient Communication</title>
        <summary>Easy Communication Between Node-RED Instances with FlowFuse</summary>
        <updated>2024-10-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Node-RED is a powerful tool for IoT application development, connecting various services and devices. However, establishing communication between different Node-RED instances—whether for monitoring or control—can be complex. This often requires detailed configurations and protocols like MQTT, HTTP, or CoAP, despite its seamless integration with many protocols.
FlowFuse addresses this challenge with project nodes designed for easy and efficient communication between Node-RED instances. This guide will show you how to use FlowFuse project nodes to enhance communication and integration, complete with practical demonstrations.&lt;/p&gt;
&lt;h2 id=&quot;what-are-flowfuse-project-nodes%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#what-are-flowfuse-project-nodes%3F&quot;&gt;What Are FlowFuse Project Nodes?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is a platform that helps manage multiple Node-RED instances in one place. This centralized management makes it easier for teams to collaborate and share resources while simplifying scaling and enhancing project security.&lt;/p&gt;
&lt;p&gt;To facilitate communication between these centrally organized instances, FlowFuse introduces specific project nodes that enable easy and secure message exchange without complex setup. Behind the scenes, these project nodes utilize MQTT, ensuring that communication is lightweight and fast.&lt;/p&gt;
&lt;p&gt;These project nodes include three main types:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image: Project nodes.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/project-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Left :Project-in node, Middle: Project-out node, Right: Project-call node&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project In&lt;/strong&gt;: Listens for messages being broadcast by other Node-RED instances or for messages sent directly to this instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project Out&lt;/strong&gt;: Sends messages to other Node-RED instances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project Call&lt;/strong&gt;:Sends messages to other Node-RED instances to trigger specific flows and waits for a response that can be sent using the project out node.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;using-flowfuse-project-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#using-flowfuse-project-nodes&quot;&gt;Using FlowFuse Project nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will explore how to use the FlowFuse project nodes. We’ll begin by explaining the Project In and Project Out nodes, followed by a detailed look at the Project Call node.&lt;/p&gt;
&lt;h3 id=&quot;using-project-in-and-out-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#using-project-in-and-out-nodes&quot;&gt;Using Project in and out nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To demostrate this nodes, we will use an example where a central instance monitors the CPU performance of multiple Node-RED instances every 10 seconds.&lt;/p&gt;
&lt;p&gt;Before we start, let’s understand their configurations:&lt;/p&gt;
&lt;h4 id=&quot;project-in-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#project-in-node&quot;&gt;Project In Node&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: A descriptive label for the node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Receive&lt;/strong&gt;: Select this option to receive messages sent specifically to this instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Receive Broadcast From&lt;/strong&gt;: Choose this option to listen for messages broadcast from other instances. A dropdown will include the names of all instances within your team.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;: This field allows you to specify a topic, similar to MQTT, to categorize the messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;project-out-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#project-out-node&quot;&gt;Project Out Node&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: A descriptive label for the node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Send Specified Project Node&lt;/strong&gt;: This option allows you to send a specific message or payload to the selected instance. Use this for one-way communication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Return Project Link Call&lt;/strong&gt;: This option sends used to sent response back using a Project Out node project call node.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Send Message To Instance&lt;/strong&gt;: A dropdown to select the instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broadcast Messages&lt;/strong&gt;: Option to send messages to all instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;: This field allows you to specify a topic, similar to MQTT, to categorize the messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;example%3A-monitoring-cpu-performance-of-node-red-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#example%3A-monitoring-cpu-performance-of-node-red-instances&quot;&gt;Example: Monitoring CPU Performance Of Node-RED Instances&lt;/a&gt;&lt;/h2&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we begin, ensure you have installed the following nodes via the Palette Manager:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-cpu&lt;/strong&gt;: This node is essential for monitoring CPU performance. Install it on the instances that you want to monitor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@flowfuse/node-red-dashboard&lt;/strong&gt;: This node is used for creating a dashboard interface. Install it on the central instance, as we will be visualizing the CPU performance data collected from the monitored instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;creating-the-flow-on-the-instances-to-monitor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#creating-the-flow-on-the-instances-to-monitor&quot;&gt;Creating the Flow on the Instances to Monitor&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this section, we will learn how to create a flow that monitors CPU performance and sends data using &lt;strong&gt;Project out&lt;/strong&gt;. We will also discuss how to make this flow reusable, allowing you to apply the same setup across multiple instances without editing the flow each time.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and set the repeat interval to &amp;quot;2 seconds&amp;quot;. This will trigger the flow after every 2 seconds.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;CPU&lt;/strong&gt; node onto the canvas. Double-click it to configure, enable the option &amp;quot;Send message for overall usage,&amp;quot; and click &amp;quot;Done&amp;quot;.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas. Configure it to add metadata, including the instance name, instance ID, using default environment variablesand and the CPU data received from the CPU node.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project Out&lt;/strong&gt; node onto the canvas. Double-click it to set the Mode to &amp;quot;Send to specified project node.&amp;quot; For the Target, select &amp;quot;Send message to instance&amp;quot; and choose the name of your centralized instance.&lt;/li&gt;
&lt;li&gt;Next, Enter the topic as &amp;quot;cpu-performance&amp;quot;.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;Inject&lt;/strong&gt; node to the input of the &lt;strong&gt;CPU&lt;/strong&gt; node, the output of the &lt;strong&gt;CPU&lt;/strong&gt; node to the input of the &lt;strong&gt;Change&lt;/strong&gt; node, and finally, connect the &lt;strong&gt;Change&lt;/strong&gt; node to the &lt;strong&gt;Project Out&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-194&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow194 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;dd182fedce6c532a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c47bc42f8a6f6884&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e0dd915a7b37af2b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:false,&#92;&quot;project&#92;&quot;:&#92;&quot;054bb5cf-20df-431f-a00b-29b28e160b27&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;cpu-performance&#92;&quot;,&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;05a9ec7b2ae57cc0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.name&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;FF_INSTANCE_NAME&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.cpu&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:560,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e0dd915a7b37af2b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c47bc42f8a6f6884&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;cpu&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;msgCore&#92;&quot;:false,&#92;&quot;msgOverall&#92;&quot;:true,&#92;&quot;msgArray&#92;&quot;:false,&#92;&quot;msgTemp&#92;&quot;:false,&#92;&quot;x&#92;&quot;:370,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;05a9ec7b2ae57cc0&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow194.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-194&#39;) })&lt;/script&gt;
&lt;p&gt;By utilizing environment variables, this flow becomes reusable, allowing you to copy and paste flow to monitor multple instances.&lt;/p&gt;
&lt;h3 id=&quot;receiving-data-to-monitor-and-visualize&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#receiving-data-to-monitor-and-visualize&quot;&gt;Receiving Data to Monitor and Visualize&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image: Line chart visualizing CPU performance of all instances.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-monitoring-chart.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image: Line chart visualizing CPU performance of all instances.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To receive the CPU data from monitored instances, follow these steps in your centralized Node-RED instance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the editor for your central instance.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project In&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;Project In&lt;/strong&gt; node and set the &lt;strong&gt;Source&lt;/strong&gt; to &amp;quot;Listen for broadcast messages from.&amp;quot; Select the name of the instances you want to monitor from the dropdown. If you want data from all instances, select &amp;quot;All instances and devices.&amp;quot;&lt;/li&gt;
&lt;li&gt;Enter the &lt;strong&gt;Topic&lt;/strong&gt; as &amp;quot;cpu-performance&amp;quot; (or the topic you configured in the Project Out nodes).&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-chart&lt;/strong&gt; widget onto the canvas. Set the chart type to &amp;quot;line&amp;quot; and configure the series to &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;Project In&lt;/strong&gt; node to the input of the &lt;strong&gt;ui-chart&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click the &amp;quot;deploy&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-195&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow195 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2d681b19eb5799b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.cpu&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;307d9c5913509557&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;307d9c5913509557&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;d0dbd4016c7aac21&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;xAxisFormat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisFormatType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;yAxisLabel&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;stackSeries&#92;&quot;:false,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;cross&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#0095ff&#92;&quot;,&#92;&quot;#ff0000&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#a347e1&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;textColor&#92;&quot;:[&#92;&quot;#666666&#92;&quot;],&#92;&quot;textColorDefault&#92;&quot;:true,&#92;&quot;gridColor&#92;&quot;:[&#92;&quot;#e5e5e5&#92;&quot;],&#92;&quot;gridColorDefault&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:8,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;465ee550bf9d101d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 1&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:false,&#92;&quot;topic&#92;&quot;:&#92;&quot;cpu-performance&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2d681b19eb5799b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0dbd4016c7aac21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Monitoring Chart&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Monitoring&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;ded86f3820342985&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/charts-example&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;chart-box-outline&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ded86f3820342985&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:true,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094CE&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow195.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-195&#39;) })&lt;/script&gt;
&lt;p&gt;Once deployed, open the dashboard to view an interactive live line chart displaying the CPU performance of all monitored devices.&lt;/p&gt;
&lt;h4 id=&quot;visualizing-data-for-specific-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#visualizing-data-for-specific-devices&quot;&gt;Visualizing Data for Specific Devices&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image: Gauges visualizing the CPU performance of different devices.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-monitoring-gauges.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image: Gauges visualizing the CPU performance of different devices.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To visualize CPU data for specific devices separately, configure the &lt;strong&gt;Project In&lt;/strong&gt; node to &amp;quot;Listen for broadcast messages from&amp;quot; and select the desired instance name that you want to monitor.&lt;/p&gt;
&lt;p&gt;In the instance sending the CPU data for monitoring, set the &lt;strong&gt;Project Out&lt;/strong&gt; node to &amp;quot;Broadcast messages.&amp;quot; This will send CPU data to all instances within your team, allowing the centralized instance to capture and display the information.&lt;/p&gt;
&lt;p&gt;If you prefer not to use broadcasting, configure the &lt;strong&gt;Project Out&lt;/strong&gt; node with specific topics. This will ensure that receiving nodes capture only specific instance data based on the topic. You can then connect these nodes to gauge nodes to distinctly display the CPU performance for each instance.&lt;/p&gt;
&lt;div id=&quot;nr-flow-196&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow196 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c0021ca894dd3e17&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.cpu&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;ui_update.label&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;932a6733d53ab87d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;426925e74d8e30f5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 1&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;04175120-ebeb-4813-8910-03f92f8ed429&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;cpu-performance&#92;&quot;,&#92;&quot;x&#92;&quot;:140,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c0021ca894dd3e17&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;932a6733d53ab87d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;087559f9b99f047a&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:10,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;38539dc4bfdbf6be&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.cpu&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;ui_update.label&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bdbcd5f9f8ac610c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e36b12aa51d365fe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 2&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;04175120-ebeb-4813-8910-03f92f8ed429&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;cpu-performance&#92;&quot;,&#92;&quot;x&#92;&quot;:140,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;38539dc4bfdbf6be&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bdbcd5f9f8ac610c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;6cf5326fe928c9cf&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:10,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a2e1fba0e9cd985a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.cpu&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;ui_update.label&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;data.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:360,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c298b64b260df708&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dcfe73c16e17648a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 3&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;8a611136-6e3f-447e-9436-34b2d00eac8e&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;cpu-performance&#92;&quot;,&#92;&quot;x&#92;&quot;:140,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a2e1fba0e9cd985a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c298b64b260df708&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ee5fc3eb29a7ee4b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;7&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:10,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;087559f9b99f047a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Group 1&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;6cf5326fe928c9cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Group 2&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ee5fc3eb29a7ee4b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Group 3&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;39fae809f6f7fc7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Device Monitoring&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;ded86f3820342985&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/charts-example&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;chart-box-outline&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;3&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;576&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;6&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;768&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;9&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:&#92;&quot;1024&#92;&quot;,&#92;&quot;cols&#92;&quot;:&#92;&quot;12&#92;&quot;}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ded86f3820342985&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:true,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5075a7d8e4947586&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094CE&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow196.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-196&#39;) })&lt;/script&gt;
&lt;p&gt;This example showcases one of many powerful use cases for FlowFuse project nodes. By utilizing these capabilities, you can transform how your Node-RED instances communicate, enabling efficient workflows and innovative solutions.&lt;/p&gt;
&lt;h2 id=&quot;using-project-call-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#using-project-call-nodes&quot;&gt;Using Project Call Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Project Call&lt;/strong&gt; nodes are ideal for triggering flows deployed on another Node-RED instance and retrieving the final result as a response. While they function similarly to &lt;a href=&quot;https://flowfuse.com/node-red/integration-technologies/webhook/&quot;&gt;webhooks&lt;/a&gt;, they utilize &lt;a href=&quot;https://flowfuse.com/node-red/protocol/mqtt/&quot;&gt;MQTT&lt;/a&gt; as their underlying mechanism instead of HTTP. In this section, we will demonstrate the use of a &lt;strong&gt;Project Call&lt;/strong&gt; node through an example of making an on-demand temperature request.&lt;/p&gt;
&lt;h3 id=&quot;how-project-call-nodes-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#how-project-call-nodes-work&quot;&gt;How Project Call Nodes Work&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Project Call&lt;/strong&gt; node does not operate in isolation; it requires both &lt;strong&gt;Project In&lt;/strong&gt; and &lt;strong&gt;Project Out&lt;/strong&gt; nodes to function properly. The &lt;strong&gt;Project Call&lt;/strong&gt; node triggers the &lt;strong&gt;Project In&lt;/strong&gt; node deployed on the specified target instance, while the &lt;strong&gt;Project Out&lt;/strong&gt; node handles the response. This means the flow that needs to be triggered should start with a &lt;strong&gt;Project In&lt;/strong&gt; node and end with a &lt;strong&gt;Project Out&lt;/strong&gt; node.&lt;/p&gt;
&lt;h3 id=&quot;example%3A-on-demand-temperature-request&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#example%3A-on-demand-temperature-request&quot;&gt;Example: On-Demand Temperature Request&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this example, we will trigger a flow on a Raspberry Pi instance that reads the temperature using a DHT11 sensor and sends the response back to the instance where we use the &lt;strong&gt;Project Call&lt;/strong&gt; node.&lt;/p&gt;
&lt;p&gt;Before we start, let’s review the configuration options for the &lt;strong&gt;Project Call&lt;/strong&gt; node:&lt;/p&gt;
&lt;h4 id=&quot;project-call-node-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#project-call-node-configuration&quot;&gt;Project Call Node Configuration&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: A descriptive label for the node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout&lt;/strong&gt;: Set the duration to wait for a response before timing out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt;: Specify the target instance where the flow is deployed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;: This field allows you to specify a topic, similar to MQTT, to categorize the messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;prerequisites-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#prerequisites-1&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Before we begin, ensure you have the following prepared:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;node-red-contrib-dht-sensor&lt;/strong&gt;: Install this node via the palette manager. This node is used to manage the connection to a DHT11 or DHT22 sensor on a Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Device Agent Setup&lt;/strong&gt;: Ensure you have set up and are running the FlowFuse device agent on your Raspberry Pi, and it is connected to the platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;developing-a-flow-to-handle-on-demand-data-requests&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#developing-a-flow-to-handle-on-demand-data-requests&quot;&gt;Developing a Flow to Handle On-Demand Data Requests&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Throughout this section, we will explore how to utilize the &lt;strong&gt;Project Call&lt;/strong&gt; node along with &lt;strong&gt;Project In&lt;/strong&gt; and &lt;strong&gt;Project Out&lt;/strong&gt; nodes to trigger a flow that retrieves temperature readings from a Raspberry Pi on demand.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Before proceeding, make sure your device is assigned to an instance. If the device is assigned to an application, you cannot use Project nodes, as they are designed to work with instances.&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-197&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow197 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;bdb27b9ab0d94897&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b152a914653d9fce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8a4fe9cf342b6156&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4ece54ca3c91f7ff&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b152a914653d9fce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:680,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8a4fe9cf342b6156&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;rpi-dht22&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;b152a914653d9fce&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;rpi-dht22&#92;&quot;,&#92;&quot;dht&#92;&quot;:&#92;&quot;11&#92;&quot;,&#92;&quot;pintype&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;pin&#92;&quot;:4,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4ece54ca3c91f7ff&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow197.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-197&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;Copy/download the flow above and import/upload it into your Raspberry Pi Node-RED instance. Ensure you have correctly interfaced the DHT11 sensor with your Raspberry Pi. For more information, refer to our guide on &lt;a href=&quot;https://flowfuse.com/node-red/hardware/raspberry-pi-4/&quot;&gt;Setting Up Node-RED on Raspberry Pi 4&lt;/a&gt;, which explains how to install the device agent on the Raspberry Pi and read temperature data from the DHT11 sensor.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you deploy the flow, you will see the temperature data displayed on the Debug panel if everything was done correctly. Now, let’s add the project nodes to trigger the temperature reading flow on demand and retrieve the data accordingly.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project In&lt;/strong&gt; node onto the canvas, double-click on it, and set the source to &amp;quot;Receive messages sent to this instance.&amp;quot; Next, enter the topic.&lt;/li&gt;
&lt;li&gt;Replace the &lt;strong&gt;Inject&lt;/strong&gt; node with the &lt;strong&gt;Project In&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Next, you can add a &lt;strong&gt;Change&lt;/strong&gt; node to format the data received by the &lt;strong&gt;DHT&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project Out&lt;/strong&gt; node onto the canvas, double-click on it, and set the mode to &amp;quot;Return to project link call.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the flow is ready, deploy it. The final flow should look like the one below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-198&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow198 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;020ede0bf68cf063&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.temperature&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;data.humidity&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;humidity&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;humidity&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;rpi-dht11&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:560,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1a592414ab69f1d8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a39fcfcd133ecaae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project in 1&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:false,&#92;&quot;topic&#92;&quot;:&#92;&quot;temperature&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;16e8a24545d3258f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a592414ab69f1d8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;project out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;return&#92;&quot;,&#92;&quot;broadcast&#92;&quot;:false,&#92;&quot;project&#92;&quot;:&#92;&quot;b1dd1d7d-556e-4dd4-9b8f-d78ffe3f510d&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;16e8a24545d3258f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;rpi-dht22&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;fe61f54c8563279d&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;rpi-dht11&#92;&quot;,&#92;&quot;dht&#92;&quot;:&#92;&quot;11&#92;&quot;,&#92;&quot;pintype&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;pin&#92;&quot;:4,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;020ede0bf68cf063&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow198.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-198&#39;) })&lt;/script&gt;
&lt;p&gt;Now that we have added the &lt;strong&gt;Project In&lt;/strong&gt; and &lt;strong&gt;Project Out&lt;/strong&gt; nodes, the flow can be triggered to read the temperature from any Node-RED instance within your team using the &lt;strong&gt;Project Call&lt;/strong&gt; node and receive the response.&lt;/p&gt;
&lt;h4 id=&quot;triggering-the-flow-and-receiving-temperature-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#triggering-the-flow-and-receiving-temperature-data&quot;&gt;Triggering the Flow and Receiving Temperature Data&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this section, we will explore how to trigger the flow we created in the previous step and receive the on-demand temperature data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the instance within your team where you want to receive the data.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Project Call&lt;/strong&gt; node onto the canvas. Double-click it to set the timeout according to your preference, then set the target to the instance where your flow needs to be triggered. Next, enter the topic you configured in the &lt;strong&gt;Project In&lt;/strong&gt; node previously.&lt;/li&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and connect it to the input of the &lt;strong&gt;Project Call&lt;/strong&gt; node. This will allow you to trigger the &lt;strong&gt;Project Call&lt;/strong&gt; node manually.&lt;/li&gt;
&lt;li&gt;Finally, drag a &lt;strong&gt;Debug&lt;/strong&gt; node onto the canvas and connect it to the output of the &lt;strong&gt;Project Call&lt;/strong&gt; node. This will help you view the response received from the triggered flow in the Debug panel.&lt;/li&gt;
&lt;li&gt;Deploy the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-199&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow199 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;8276fba516f3697b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;project link call&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;project&#92;&quot;:&#92;&quot;d1b6cf3a-70fc-4ec4-b30c-e207338b2cc4&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;temperature&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9ef6638382d7e9d5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0abdbf43350eb362&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8276fba516f3697b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9ef6638382d7e9d5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d382bd2b5733a3a9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow199.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-199&#39;) })&lt;/script&gt;
&lt;p&gt;Now, once you click the &lt;strong&gt;Inject&lt;/strong&gt; button, you will see the response that includes the temperature in the debug panel, which is read by the flow deployed on the Raspberry Pi.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the project call node triggering the flow to read the temperature data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/project-out-node-triggering-flow.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the project call node triggering the flow deployed on the device to read the temperature data.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that you understand how to use FlowFuse project nodes, you can significantly improve the way your Node-RED instances communicate with one another.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/exploring-flowfuse-project-nodes/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse project nodes streamline communication between Node-RED instances. By using these nodes, you can easily monitor performance, request data, and more. This makes your workflows smoother and more efficient.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/</id>
        <title>Creating and Automating DevOps Pipelines for Node-RED in Industrial Environments</title>
        <summary>Streamlining Deployments for Efficiency and Safety in Industrial Environments</summary>
        <updated>2024-10-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;When deploying any update in your manufacturing or automotive process, it is important to perform testing and validation. The smallest errors can lead to a production outage. In such cases, having a quick and reliable deployment process is essential for maximising uptime and minimising downtime.
For developers using Node-RED, setting up a comprehensive DevOps pipeline can make all the difference. In this blog, we’ll explore how to build and automate DevOps pipelines specifically for Node-RED deployments. You’ll discover practical tips and tools to streamline your process, ensuring your applications are always ready to support your operations.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-a-devops-pipeline%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/#what-exactly-is-a-devops-pipeline%3F&quot;&gt;What Exactly is a DevOps Pipeline?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the DevOps Lifecycle&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/What-is-DevOps.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The DevOps Lifecycle illustrating the stages of development through to production&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A DevOps pipeline is an process that helps developers move their code from development to production smoothly. In a pipeline, each step depends on the one before it, ensuring every update is properly tested and ready for use. The most common stages of a pipeline are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Development:&lt;/strong&gt; This is where the application flows are created. A level of testing and checking is carried out as a natural step of the development.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Staging/Testing:&lt;/strong&gt; In this stage, the code is deployed to a staging environment that closely mimics the live system. Here, the application goes through a level of QA and is tested in scenarios as close to real-world conditions as possible. This is stage designed to catch any issues that slipped through in the development stage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production:&lt;/strong&gt; When the flows are tested and confirmed in staging and are ready to be deployed, this stage can be operated to promote the flows to production.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;how-to-create-devops-pipelines-for-node-red-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/#how-to-create-devops-pipelines-for-node-red-deployments&quot;&gt;How to Create DevOps Pipelines for Node-RED Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Creating DevOps pipelines manually for your Node-RED deployments can be time-consuming, expensive, and require considerable technical expertise. &lt;strong&gt;FlowFuse&lt;/strong&gt; simplifies the creation of DevOps pipelines for Node-RED deployments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; enhances collaboration, security, and scalability for your Node-RED applications, making the deployment and management of edge devices seamless. With a centralized platform and an intuitive visual interface, FlowFuse allows you to connect, collect, transform, and visualize data effortlessly.&lt;/p&gt;
&lt;h3 id=&quot;steps-to-create-a-devops-pipeline%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/#steps-to-create-a-devops-pipeline%3A&quot;&gt;Steps to Create a DevOps Pipeline:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;FlowFuse platform&lt;/strong&gt; and navigate to the application where your Node-RED instances are located. Ensure you have instances set up for all stages, including production devices or instances.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;DevOps Pipelines&lt;/strong&gt; option from the top menu.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing option to switch to DevOps pipelines tab from top menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devops-pipeline-option-in-apps.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing option to switch to DevOps pipelines tab from top menu&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click the &lt;strong&gt;Add Pipeline&lt;/strong&gt; button in the top right corner to create the pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the FlowFuse dashboard with the &#39;Add Pipeline&#39; button highlighted at the top-right corner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-pipeline-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Click the &#39;Add Pipeline&#39; button to start creating your DevOps pipeline in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Enter the name for your pipeline and click &lt;strong&gt;Create Pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the pipeline creation form in FlowFuse, showing fields to enter the pipeline&#39;s name&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-to-create-pipeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Fill out the form to give your pipeline a name&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Next, you&#39;ll see an option to create stages by clicking &lt;strong&gt;Add Stage&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot highlighting the button to add stages within a DevOps pipeline in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/button-to-add-stages.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Add stages to your pipeline for different deployment environments, such as development, testing, and production&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;In the window that opens, select the &lt;strong&gt;stage type&lt;/strong&gt; based on whether it&#39;s an instance, device, or device group.&lt;/li&gt;
&lt;li&gt;Enter the name for the stage in the &lt;strong&gt;Stage Name&lt;/strong&gt; field.&lt;/li&gt;
&lt;li&gt;Choose an instance, device, or device group for the stage.&lt;/li&gt;
&lt;li&gt;Next, configure which action should be performed when this stage is pushed to the next:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create New Snapshot:&lt;/strong&gt; Generates a new &lt;a href=&quot;https://flowfuse.com/docs/user/high-availability/&quot;&gt;Snapshot&lt;/a&gt; using the current flows and settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Latest Instance Snapshot:&lt;/strong&gt; Uses the most recent existing snapshot of the instance. The deployment will fail if no snapshot exists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt to Select Snapshot:&lt;/strong&gt; Prompts at deploy time to select which snapshot from the source stage should be copied to the next stage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Check the option &lt;strong&gt;Deploy to Devices&lt;/strong&gt; if you want changes to be deployed to all devices connected to this stage’s instance when the stage is deployed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the stage configuration form with options to select instance types and configure actions.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-to-create-configure-stages.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configure each stage by selecting an instance, device, or device group, and define the deployment actions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once you’ve created your initial stage, you can add more stages by following the same process. This flexibility allows you to tailor your DevOps pipeline to meet the specific needs of your Node-RED deployment.&lt;/p&gt;
&lt;p&gt;For example, in development, you might have a Node-RED instance in the cloud to build your application. During staging, you could test the setup with a single device. Finally, in production, you can deploy the tested application to thousands of devices in a device group, saving time and ensuring smooth deployment at scale.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;DevOps pipelines animation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devops-pipeline.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image: DevOps animation demonstrating pipeline deployments.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;running-a-pipeline-stage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/#running-a-pipeline-stage&quot;&gt;Running a Pipeline Stage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once your pipeline is set up, you can run it to deploy your changes across each stage. Here&#39;s how:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the &#39;Run Pipeline&#39; button in FlowFuse, allowing users to trigger the deployment process.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/button-to-run-pipeline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Click the &#39;Run Pipeline&#39; button to initiate a pipeline deployment.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click the &amp;quot;Run Pipeline&amp;quot; button for the current stage to start the deployment. This button is available for all stages except the last one.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After clicking, the deployment automatically progresses to the next stage on the right. Since each pair of stages operates independently, you need to click the &amp;quot;Run&amp;quot; button for each stage to continue the deployment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pressing the &amp;quot;Run Pipeline&amp;quot; button for the current stage creates a new snapshot that includes all settings, environment variables, and flows for that stage. This snapshot is then copied and deployed to the next stage, but any existing environment variable keys in the target stage will remain unchanged.&lt;/p&gt;
&lt;p&gt;When creating a pipeline, you can include only one Device Group, and it must be in the final stage. This ensures all changes are fully tested and verified before reaching production, guaranteeing a safe and reliable deployment.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/10/how-to-build-automate-devops-pipelines-node-red-deployments/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DevOps pipelines formalize deployment patterns, standardize testing, and streamline updates, minimizing errors and downtime. This clear process improves reliability and helps organizations adapt more easily thus ensuring smooth operation of critical applications in manufacturing and automotive environments.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/</id>
        <title>Using Snapshots for Version Control in Node-RED with FlowFuse</title>
        <summary>Effortlessly manage and recover your Node-RED flows with snapshots in FlowFuse.</summary>
        <updated>2024-09-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/"/>
        <author><name>Sumit Shinde</name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Version control is essential, especially when multiple people are working on the same Node-RED project. Without it, changes can easily overlap, or worse — accidental updates could break critical flows. FlowFuse solves this challenge with snapshots, allowing you to create backups of your flows, restore previous versions, and safeguard your project from unexpected issues.&lt;/p&gt;
&lt;p&gt;Let&#39;s look at how to use snapshots in FlowFuse to manage your Node-RED projects with confidence and prevent costly mistakes.&lt;/p&gt;
&lt;h2 id=&quot;what-is-version-control-and-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#what-is-version-control-and-snapshots&quot;&gt;What is Version Control and Snapshots&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;strong&gt;version control&lt;/strong&gt; for Node-RED flows can introduce complexity and effort, as it often requires frequent pushes of changes to keep everything in sync. This is especially challenging in environments where modifications occur rapidly and continuously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Snapshots&lt;/strong&gt; simplify this process by providing point-in-time backups of your flows. In the context of Node-RED, snapshots automatically capture the state of your work, ensuring that you can quickly restore them if needed. It captures the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flows&lt;/strong&gt;: The flow, including all nodes and config nodes of your Node-RED flows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credentials&lt;/strong&gt;: Any sensitive information used within flows using config nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment Variables&lt;/strong&gt;: Environment variables you have used or defined within that Node-RED instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Packages&lt;/strong&gt;: The packages you have installed, including 3rd party contribution nodes and Node.js packages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime Settings&lt;/strong&gt;: The configurations that govern the behavior of your Node-RED runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With snapshots in &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;, you can focus on developing your projects while having the confidence that your work is protected.&lt;/p&gt;
&lt;h2 id=&quot;managing-snapshots-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#managing-snapshots-in-flowfuse&quot;&gt;Managing Snapshots in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Creating snapshots in FlowFuse is straightforward and can be done in just a few steps.&lt;/p&gt;
&lt;h3 id=&quot;creating-snapshots-for-cloud-and-device-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#creating-snapshots-for-cloud-and-device-instances&quot;&gt;Creating Snapshots for Cloud and Device Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we begin, it’s essential to understand the differences between a cloud instance and a device instance. For more information, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#instance&quot;&gt;Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, let’s discuss the two types of device assignments available in FlowFuse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Application Device
&lt;ul&gt;
&lt;li&gt;When a device is assigned to an instance, it can be considered as a mirror of the instance. In Fleet mode, it downloads and runs the target snapshot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Instance Device
&lt;ul&gt;
&lt;li&gt;When a device is assigned to an application, it can be considered as a standalone entity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that in mind, taking snapshots for an Application Device is a bit different from taking a snapshot for an Instance Device. For example, taking snapshots of an Application Device will have the same user experience as taking a snapshot of a cloud instance. However, since an Instance Device is typically closely coupled with the owner instance, there is a slightly different procedure. We will cover both below.&lt;/p&gt;
&lt;h4 id=&quot;creating-snapshots-for-cloud-instance-and-application-device&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#creating-snapshots-for-cloud-instance-and-application-device&quot;&gt;Creating Snapshots for Cloud Instance and Application Device&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &amp;quot;Instances&amp;quot; option in the sidebar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/instances-option-in-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &amp;quot;Instances&amp;quot; option in the sidebar&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &amp;quot;Devices&amp;quot; option in the sidebar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/devices-option-in-the-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &amp;quot;Devices&amp;quot; option in the sidebar&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to your FlowFuse account and navigate to the instances by clicking on &lt;strong&gt;&amp;quot;Instances&amp;quot;&lt;/strong&gt; in the sidebar, or if you want to create a snapshot for an Application Device, click on &lt;strong&gt;&amp;quot;Devices.&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click on the instance or device you want to create a snapshot for. This will take you to the management interface, which includes different tabs for various settings.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the option to switch to the Snapshots tab in FlowFuse Cloud Instance.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/option-to-switch-to-snapshots-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the option to switch to the Snapshots tab in FlowFuse Cloud Instance.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the option to switch to the Snapshots tab in FlowFuse Application Device.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/application-device-snapshot-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the option to switch to the Snapshots tab in FlowFuse Application Device.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Switch to the &lt;strong&gt;“Snapshots”&lt;/strong&gt; tab by selecting it from the instance management options. Here, you will find options to create a new snapshot called &lt;strong&gt;&amp;quot;Create Snapshot&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the button to create a snapshot in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/button-to-create-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the button to create a snapshot in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click on the button to &lt;strong&gt;create snapshot&lt;/strong&gt;. You will be prompted to enter a &lt;strong&gt;name and description&lt;/strong&gt; for the snapshot, helping you identify it later. There’s also an option to set this snapshot as Device Target Snapshot — enable this checkbox if needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the form to provide a name and description for the snapshot.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-to-give-snapshot-name-desc.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the form to provide a name and description for the snapshot.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;After creating the snapshot, you will receive a confirmation message indicating that the snapshot has been successfully created.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing a list of created snapshots with details in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/snapshot-in-the-list.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing a list of created snapshots with details in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once a snapshot is created, it will be visible in a list format. Each snapshot will display details such as the name, description, creator, and creation date, along with a three-dot icon.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing available options for managing snapshots in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/options-available-for-instance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing available options for managing snapshots in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Clicking on the icon will open different options to manage and operate the snapshot.&lt;/p&gt;
&lt;h3 id=&quot;creating-snapshot-for-device-instances-when-assigned-to-cloud-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#creating-snapshot-for-device-instances-when-assigned-to-cloud-instance&quot;&gt;Creating Snapshot for Device Instances when assigned to Cloud Instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the device is in fleet mode, it will be running the flows specified by the target snapshot, and there is typically no need to create a snapshot directly from the device. However, if the device is in developer mode, it may have been modified and may have different flows than those in the instances. In this case, you can take a snapshot directly from the device using the Developer Mode tab. Here’s how to do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Devices&lt;/strong&gt; by clicking on the &lt;strong&gt;Devices&lt;/strong&gt; option in the sidebar, and then click on the specific device.&lt;/li&gt;
&lt;li&gt;Once clicked, a similar interface will open as with instances, allowing you to manage and monitor its settings and configuration. Ensure that the device has developer mode enabled.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Create Snapshot&#39; option in the Developer mode tab&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/option-to-create-device-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Create Snapshot&#39; option in the Developer mode tab&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Developer Mode&lt;/strong&gt; tab by clicking on the &lt;strong&gt;Developer Mode&lt;/strong&gt; option at the top. In the Developer Mode section, you will see the &lt;strong&gt;Create Snapshot&lt;/strong&gt; button. Click on it to create a snapshot, then enter the details such as the name and description. If needed, set it as the device target snapshot, and then click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;viewing-and-comparing-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#viewing-and-comparing-snapshots&quot;&gt;Viewing and Comparing Snapshots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the &lt;strong&gt;Snapshots&lt;/strong&gt; tab, you can view all snapshots associated with your instance. FlowFuse also allows you to compare two snapshots, enabling you to track changes between different versions of your flows. This is especially useful for identifying specific changes that may have caused issues or to review the progress over time.&lt;/p&gt;
&lt;h4 id=&quot;viewing-a-snapshot%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#viewing-a-snapshot%3A&quot;&gt;Viewing a Snapshot:&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;View Snapshot&#39; option in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/view-snapshot-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;View Snapshot&#39; option in the menu&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the three-dot icon next to the corresponding snapshot you want to view, then select &lt;strong&gt;View Snapshot&lt;/strong&gt; from the menu.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the snapshot view window in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/view-snapshot-window.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the snapshot view window in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;After clicking, a new window will open displaying the entire flow for that snapshot. At the bottom right of this window, you&#39;ll find options to &lt;strong&gt;copy&lt;/strong&gt; or &lt;strong&gt;download&lt;/strong&gt; the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;comparing-snapshots%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#comparing-snapshots%3A&quot;&gt;Comparing Snapshots:&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you have multiple snapshots and want to compare them, follow these steps:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Compare Snapshot&#39; option in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compare-snapshot-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Compare Snapshot&#39; option in the menu&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the three-dot icon next to the snapshot you want to compare, then choose &lt;strong&gt;Compare Snapshot&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the comparison window in FlowFuse, featuring a dropdown to select the instance to compare and a compare button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/window-comparing-snapshots.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the comparison window in FlowFuse, featuring a dropdown to select the instance to compare and a compare button&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In the newly opened window, select another snapshot from the dropdown to compare it with the one you chose.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the comparison window for snapshots in FlowFuse, with differences highlighted in light purple color.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/window-comparing-snapshots-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the comparison window for snapshots in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;The flows of both snapshots will be displayed side by side. At the top-right corner of the window, you will see two buttons, Use according to your preference:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prev&lt;/strong&gt;: Navigate to the previous difference between the two snapshots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Next&lt;/strong&gt;: Navigate to the next difference.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This comparison feature helps you easily identify changes, making it simple to spot issues or track flow modifications between versions.&lt;/p&gt;
&lt;h3 id=&quot;downloading%2C-uploading%2C-and-deploying-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#downloading%2C-uploading%2C-and-deploying-snapshots&quot;&gt;Downloading, Uploading, and Deploying Snapshots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Created snapshots can be downloaded locally, providing you with a backup of your Node-RED flows. This backup can be uploaded to another instance or restored in case of emergencies.&lt;/p&gt;
&lt;h4 id=&quot;downloading-snapshot%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#downloading-snapshot%3A&quot;&gt;Downloading Snapshot:&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Download Snapshot&#39; option in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/download-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Download Snapshot&#39; option in the menu&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the &lt;strong&gt;three-dot&lt;/strong&gt; icon next to the corresponding snapshot, then select &lt;strong&gt;Download Snapshot&lt;/strong&gt; from the menu.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the prompt to download a snapshot in FlowFuse, featuring a highlighted key and the download button.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/download-snapshot-prompt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the prompt to download a snapshot in FlowFuse, featuring a highlighted key and the download button&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;A &lt;strong&gt;Download Snapshot&lt;/strong&gt; dialog will open.  Note: If the flows contain sensitive values, an additional field for &lt;strong&gt;secret key&lt;/strong&gt; will be displayed. This is used to encrypt the sensitive values in the snapshot. As a convenience, a random secret is auto generated however you should change this to something memorable as it will be needed when you later upload the snapshot.&lt;/li&gt;
&lt;li&gt;Next, click the &lt;strong&gt;Download&lt;/strong&gt; button located at the bottom right of the prompt to download the snapshot.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;uploading-snapshots%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#uploading-snapshots%3A&quot;&gt;Uploading Snapshots:&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the button to upload a snapshot in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/button-upload-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the button to upload a snapshot in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Snapshots&lt;/strong&gt; tab, click the &lt;strong&gt;Upload Snapshot&lt;/strong&gt; button at the top-right corner.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the prompt to upload a snapshot in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/upload-prompt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the prompt to upload a snapshot in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Select the snapshot file from your local system. If a secret key was provided during the snapshot download, enter it. Otherwise, you will not be prompted for a key.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload&lt;/strong&gt; to restore the snapshot to the desired instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With this process, you can easily manage your snapshots across different environments, ensuring the safety and portability of your Node-RED flows.&lt;/p&gt;
&lt;h4 id=&quot;deploying-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#deploying-snapshots&quot;&gt;Deploying Snapshots&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Once you have learned how to download and upload snapshots, deploying them is quite straightforward.&lt;/p&gt;
&lt;p&gt;To deploy a snapshot:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Deploy Snapshot&#39; option in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/deploy-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Deploy Snapshot&#39; option in the menu&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the three-dot icon next to the corresponding snapshot and select &lt;strong&gt;Deploy Snapshot&lt;/strong&gt; from the menu.&lt;/li&gt;
&lt;li&gt;Next, you will be prompted to confirm the deployment. Review the details to ensure you are deploying the correct snapshot.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Confirm&lt;/strong&gt; to proceed with the deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Upon successful deployment, the instance will restart with the state captured in the snapshot. This includes all flows, credentials, environment variables, NPM packages, and runtime settings as they were at the time of the snapshot. This process allows you to quickly recover from issues or revert to a previously stable state in your Node-RED instance.&lt;/p&gt;
&lt;h2 id=&quot;introducing-auto-snapshot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#introducing-auto-snapshot&quot;&gt;Introducing Auto Snapshot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Creating snapshots is crucial for documenting changes, and manually creating them gives users full control over when snapshots are taken. However, manually doing this can be time-consuming, and there is always the risk of forgetting to create one before making changes. To simplify this process, FlowFuse introduces the &lt;strong&gt;Auto Snapshot&lt;/strong&gt; feature.&lt;/p&gt;
&lt;p&gt;Auto Snapshots automatically create backups whenever you deploy changes, ensuring that your work is continuously backed up without requiring manual intervention. These snapshots are labeled as &lt;strong&gt;&amp;quot;Auto snapshot - yyyy-mm-dd hh:mm:ss&amp;quot;&lt;/strong&gt; for easy identification.&lt;/p&gt;
&lt;p&gt;This feature allows you to focus on developing your Node-RED flows with the assurance that your changes are securely saved. If necessary, you can disable Auto Snapshots for devices only from the &lt;strong&gt;Developer Mode&lt;/strong&gt; tab. This can be helpful to avoid excessive data usage when a device is in the field or on a cellular connection, or to prevent reaching the limit of auto snapshots with unnecessary snapshots.&lt;/p&gt;
&lt;h3 id=&quot;disabling-auto-snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#disabling-auto-snapshots&quot;&gt;Disabling Auto Snapshots&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Developer Mode&lt;/strong&gt; tab by clicking on the &amp;quot;Developer Mode&amp;quot; option at the top.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing option to enable/disable auto-snapshots for devices&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/enable-disable-auto-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing option to enable/disable auto-snapshots for devices&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Once inside the Developer Mode tab, you will find the option to enable or disable the Auto Snapshot feature.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A limit of 10 auto snapshots is maintained, with the oldest one being deleted when a new one is created. Also this feature is only available to &lt;strong&gt;Team&lt;/strong&gt; and &lt;strong&gt;Enterprise&lt;/strong&gt; users.&lt;/p&gt;
&lt;h2 id=&quot;setting-a-device-target-snapshot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#setting-a-device-target-snapshot&quot;&gt;Setting a Device Target Snapshot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you set a device target snapshot, all devices associated with the instance will be restarted and updated to run that specified snapshot. This gives you full control over when devices receive the latest changes from your development instance.&lt;/p&gt;
&lt;p&gt;With this feature, you can continue developing and testing your flows in FlowFuse without immediately impacting your devices. Once you&#39;re confident the flow is ready, you can push the changes to the devices by setting the target snapshot.&lt;/p&gt;
&lt;p&gt;Device target snapshots can be assigned either during the creation of a snapshot or at a later time.&lt;/p&gt;
&lt;h3 id=&quot;to-set-the-already-creted-snapshot-as-a-device-target-snapshot%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#to-set-the-already-creted-snapshot-as-a-device-target-snapshot%3A&quot;&gt;To set the already creted Snapshot as a Device Target Snapshot:&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;Snapshots&lt;/strong&gt; tab and click on the three-dot icon next to the desired snapshot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the &#39;Set as Device Target&#39; option in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-targe-snapshot-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the &#39;Set as Device Target&#39; option in the menu&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Select &lt;strong&gt;Set as Device Target&lt;/strong&gt; from the menu, prompt will open to conform then click on to the &amp;quot;Set Target&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the green status indicating how many devices have deployed this snapshot option in the menu.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/status-showing-the-target-snapshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the green status indicating how many devices have deployed this snapshot option in the menu.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once done you will be able to see the green mark in that snapshot showing on how much devices it is deployed on.&lt;/p&gt;
&lt;h2 id=&quot;common-mistakes-to-avoid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#common-mistakes-to-avoid&quot;&gt;Common Mistakes to Avoid&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Neglecting Regular Backups&lt;/strong&gt;: Don’t skip those snapshots! Regularly create backups, especially before making significant changes, moving devices through instances or applications, or disabling developer mode. Think of it as your safety net—ensuring you can always bounce back to a stable state if unexpected issues pop up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Overlooking Auto-Snapshot Limits&lt;/strong&gt;: Did you know that your &lt;strong&gt;auto snapshots&lt;/strong&gt; have limits? Be mindful of how many you can retain, as older &lt;strong&gt;auto snapshots&lt;/strong&gt; will be automatically deleted. If you have important &lt;strong&gt;auto snapshots&lt;/strong&gt;, either rename them to avoid automatic deletion or download and save them locally to keep them safe. Remember, manually created snapshots have no limits, so take advantage of that!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secret Key&lt;/strong&gt;: The secret key used to encrypt your snapshot is crucial for when you later need to upload that snapshot. When downloading snapshots locally, securely store that key. Losing it could mean losing access to your snapshot and your ability to recover your work. Treat it like a password—keep it safe!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Taking a Snapshots of the wrong thing&lt;/strong&gt;: When a device is owned by an instance it typically runs the same flows however, if a device flows may have been modified directly in &lt;strong&gt;developer mode&lt;/strong&gt; it will have different flows to the instance that owns it. In this case, before you move the device or switch it out of developer mode, it is recommended that you take a snapshot directly from the device itself. Direct device snapshots are performed on the &lt;strong&gt;Developer Mode&lt;/strong&gt; tab of the device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deploying Unverified Snapshots&lt;/strong&gt;: A little caution goes a long way! Always review and verify the details of a snapshot before deploying it. Jumping into deployment without checking can lead to unexpected behavior or the loss of critical configurations. Take the time to ensure everything is in order.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/node-red-version-control-with-snapshots/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using snapshots in FlowFuse is an effective way to manage your Node-RED projects with confidence. By regularly creating snapshots, you can ensure that you always have a backup of your work, allowing you to quickly recover from mistakes or accidental changes.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/</id>
        <title>FlowFuse 2.9: Software Bill of Materials &amp; Public Static Assets</title>
        <summary>Let&#39;s take a look at the new features and improvements in FlowFuse 2.9</summary>
        <updated>2024-09-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.9 bring improvements in application maintenance with the new &amp;quot;Software Bill of Materials&amp;quot; and in building full stack applications, with an iteration on the &amp;quot;Static Asset Service&amp;quot;, by providing the option to &amp;quot;share&amp;quot; your assets assets publicly, making them consumable by external services and your Dashboards.&lt;/p&gt;
&lt;h2 id=&quot;software-bill-of-materials&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#software-bill-of-materials&quot;&gt;Software Bill of Materials&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This release sees the introduction of a new feature for our Enterprise customers, the Software Bill of Materials (SBOM).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Software Bill of Materials view in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-sbom.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This view is available for all of your Applications in FlowFuse, and provides a detailed breakdown of all packages running in your Node-RED instances within your applications, making it easier to trace down out of date packages and keep on top of the security and integrity of your applications.&lt;/p&gt;
&lt;p&gt;In the above screenshot, we get a clear picture of the different versions of Node-RED that I&#39;m running, as well as the different packages that are installed in each of my instances. Highlighting in particular that I have some out-of-date versions of &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s possible to expand the detail for each entry to see which instances are running the respective package, and consequently jump in to update them if appropriate.&lt;/p&gt;
&lt;h2 id=&quot;static-assets-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#static-assets-service&quot;&gt;Static Assets Service&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/&quot;&gt;Last release&lt;/a&gt; we published the new &amp;quot;Static Assets Service&amp;quot;. This new feature provided an easy way to upload files alongside your Node-RED instances, and make them easily accessible in your Node-RED Editor.&lt;/p&gt;
&lt;p&gt;In this new release we&#39;ve expanded on that feature, now allowing you to make those files publicly accessible via a URL, making them available for consumption in your Dashboards, or wherever else you may want to consume that content.&lt;/p&gt;
&lt;video controls=&quot;&quot;&gt;
   &lt;source src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/Assets+Service+Demo+-+Part+2.mp4&quot; type=&quot;video/mp4&quot; /&gt;
   Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;This unlocks a new set of possibilities for building full stack applications in FlowFuse, for examples, making it easy to customize branding in your Dashboard to match your company&#39;s branding, or to serve up images and other assets to your users.&lt;/p&gt;
&lt;h2 id=&quot;and-much-more...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#and-much-more...&quot;&gt;And Much More...&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.9 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.9.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;coming-soon%3A-mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#coming-soon%3A-mqtt-broker&quot;&gt;Coming Soon: MQTT Broker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse already makes extensive use of MQTT under the covers. It provides the connection for our &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;Project Nodes&lt;/a&gt; that make it very simple to move data between your Node-RED instances.&lt;/p&gt;
&lt;p&gt;We&#39;re now working on opening up the broker to allow teams to connect their MQTT devices to the platform without having to manage their own broker infrastructure.&lt;/p&gt;
&lt;p&gt;This feature will allow you to run and manage your own MQTT Clients alongside your Node-RED instances, making it easier to build full-stack IoT applications with FlowFuse.&lt;/p&gt;
&lt;p&gt;We do not have a precise release date for this just yet, but we&#39;re hoping to having this in for 2.10 or 2.11. Keep an eye out for more information on this in the coming weeks. If this feature is of interest to you, please do &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;reach out&lt;/a&gt; and help us shape it to make sure it meets your needs.&lt;/p&gt;
&lt;h2 id=&quot;try-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#try-flowfuse&quot;&gt;Try FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.9, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have an Enterprise license please make sure to review this &lt;a href=&quot;https://flowfuse.com/changelog/2024/08/enterprise-license-update/&quot;&gt;changelog entry&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/flowfuse-release-2-9/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/</id>
        <title>How to Scrape Data from Websites Using Node-RED</title>
        <summary>A step-by-step guide to leveraging Node-RED for efficient web scraping and automated data extraction.</summary>
        <updated>2024-09-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Web scraping has become an indispensable tool for monitoring news, tracking competitors, and gathering insights. In this guide, you&#39;ll learn how to harness the power of Node-RED for efficient web scraping, allowing you to extract and manage data from various websites with ease that are not exposed through an API.&lt;/p&gt;
&lt;h2 id=&quot;what-is-web-scraping%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#what-is-web-scraping%3F&quot;&gt;What is Web Scraping?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web scraping is a technique for automatically extracting data from websites. Instead of manually copying information from web pages, web scraping uses tools or scripts to access and retrieve data from the Internet efficiently. This process allows you to quickly gather large volumes of information, which is helpful for tasks such as tracking market trends, aggregating news, or collecting product details. By automating data collection, web scraping helps save time and reduce human error. It enables users to extract and analyze structured data from various sources, making it easier to compile and utilize information for research, business intelligence, or other purposes.&lt;/p&gt;
&lt;p&gt;Web scraping can be helpful when APIs are unavailable or do not meet your requirements. It allows you to collect data directly from web pages, which can be beneficial for tasks like competitive analysis, market research, or tracking specific online content.&lt;/p&gt;
&lt;h2 id=&quot;how-does-web-scraping-works%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#how-does-web-scraping-works%3F&quot;&gt;How Does Web Scraping Works?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web scraping involves systematically extracting data from websites using automated tools or scripts. The process begins with requesting a specific webpage. The response from the server is the HTML content of the page. This HTML code contains the structured information displayed on the webpage, organized in a format that describes the layout and content.&lt;/p&gt;
&lt;p&gt;Once the HTML is received, the next step is parsing it. Parsing involves analyzing the HTML structure to identify and extract the data of interest. This may include navigating through nested elements, locating specific tags, and using selectors to target precise content such as text blocks, images, or links. The extracted data is then processed and stored in a format that suits the user&#39;s needs, whether a database, a CSV file, or another format suitable for analysis.&lt;/p&gt;
&lt;h2 id=&quot;web-scrapping-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#web-scrapping-with-node-red&quot;&gt;Web scrapping with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will guide you through the process of scraping data from publicly available websites using Node-RED and demonstrate how to extract data from a website specifically designed for scraping practice. For this example, we will scrape country data from the page at &lt;code&gt;https://www.scrapethissite.com/pages/simple/.&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;sending-requests-to-a-webpage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#sending-requests-to-a-webpage&quot;&gt;Sending Requests to a Webpage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To start scraping data, follow these steps to send an HTTP GET request to the webpage:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas. This node allows you to manually trigger the HTTP request or set it to fire at specific intervals.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;http request&lt;/strong&gt; node onto the canvas. Double-click it to configure and set the &lt;strong&gt;Method&lt;/strong&gt; to &lt;code&gt;GET.&lt;/code&gt; Enter the webpage URL you want to scrape (e.g., &lt;code&gt;https://www.scrapethissite.com/pages/simple/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;inject&lt;/strong&gt; node&#39;s output to the input of the &lt;strong&gt;http request&lt;/strong&gt; node and the &lt;strong&gt;http request&lt;/strong&gt; node&#39;s output to the input of the &lt;strong&gt;debug&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to save and deploy your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once deployed, click the &lt;strong&gt;inject&lt;/strong&gt; button. You will see the raw HTML printed in the debug panel.&lt;/p&gt;
&lt;h3 id=&quot;parsing-and-extracting-data-from-html&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#parsing-and-extracting-data-from-html&quot;&gt;Parsing and Extracting Data from HTML&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, we need to process the raw HTML to extract meaningful data. This involves parsing the HTML content and identifying the specific information you want. To do this, first analyze the HTML structure of the webpage by opening the browser’s developer tools (press Ctrl + I or F12) and inspecting the elements to locate where the data is and in which HTML elements it resides.&lt;/p&gt;
&lt;h4 id=&quot;analyzing-html-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#analyzing-html-structure&quot;&gt;Analyzing HTML Structure&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Begin by analyzing the HTML structure of the webpage. Open your browser’s developer tools (press Ctrl + Shift + c ) and examine the elements to locate where the data resides and which HTML elements contain it. For example, on a page with a list of countries, each with its capital, population, and area, click on one of those countires elements to navigate to its HTML in the developer tools. Identify the selector that can be used to select those elements. On this webpage, the information about countries is contained within an element with the .countries class. You can use this class to extract all the data for the countries.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the structure of the page and the data which we needed to extract&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/html-structer-of-target-website.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the structure of the page and the data which we needed to extract&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;using-node-red-to-extract-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#using-node-red-to-extract-data&quot;&gt;Using Node-RED to extract data&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;html&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;html&lt;/strong&gt; node and enter the selector &lt;code&gt;.countries&lt;/code&gt; into the &amp;quot;Selector&amp;quot; field.&lt;/li&gt;
&lt;li&gt;Set the output to &amp;quot;only the text of element&amp;quot; and keep other settings default.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;http request&lt;/strong&gt; node to the input of the &lt;strong&gt;html&lt;/strong&gt; node and the output of the &lt;strong&gt;html&lt;/strong&gt; node to the input of the &lt;strong&gt;debug&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; to save and deploy your flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When you click the &lt;strong&gt;inject&lt;/strong&gt; button, you will see the array containing the text content from each &lt;code&gt;.countries&lt;/code&gt; div. While this data is a good starting point, it has yet to be in a format that is directly useful for analysis. To make the data more helpful, you&#39;ll need to transform it into objects with meaningful properties.&lt;/p&gt;
&lt;h3 id=&quot;transforming-data-into-structured-objects&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#transforming-data-into-structured-objects&quot;&gt;Transforming Data into Structured Objects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can use JavaScript in a Node-RED function node to transform data into structured objects. If you are familiar with JavaScript, this process will be straightforward. However, if you are not, you can use FlowFuse Expert to generate the necessary function. For more details, refer to our &lt;a href=&quot;https://www.linkedin.com/posts/flowfuse_flowfuse-nodered-automation-activity-7226171132796637184-vKKt/?utm_source=share&amp;amp;utm_medium=member_desktop&quot;&gt;LinkedIn Post&lt;/a&gt; for a quick guide. However, in this section, we will use a low-code approach to transform the data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;HTML&lt;/strong&gt; node. This &lt;strong&gt;Split&lt;/strong&gt; node will split the input array into individual string messages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Split&lt;/strong&gt; node. Set &lt;code&gt;msg.name&lt;/code&gt; to the following JSONata expression to extract the country name:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-132&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-132&quot; class=&quot;language-json&quot;&gt;$trim($split(payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Capital: &quot;&lt;/span&gt;)&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-132&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the following Jsonata expression that will extract the capital and population from the string:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-138&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-138&quot; class=&quot;language-json&quot;&gt;$split($split(payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Capital: &quot;&lt;/span&gt;)&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Population: &quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-138&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the previous &lt;strong&gt;Change&lt;/strong&gt; node. Set &lt;code&gt;msg.capital&lt;/code&gt; to the following Jsonata expression to trim and extract the value of the capital from the previously split data array:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-144&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-144&quot; class=&quot;language-json&quot;&gt;$trim(payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-144&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the following Jsonata expression to split the remaining string for area extraction:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-150&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-150&quot; class=&quot;language-json&quot;&gt;$split(payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Area (km2): &quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-150&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the &lt;strong&gt;Change&lt;/strong&gt; node from the previous step. Set &lt;code&gt;msg.population&lt;/code&gt; to the following Jsonata expression to trim and convert the population value to a number:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-156&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-156&quot; class=&quot;language-json&quot;&gt;$number($trim(payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-156&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;msg.area&lt;/code&gt; to the following Jsonata expression to trim and convert the area value to a number:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-162&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-162&quot; class=&quot;language-json&quot;&gt;$number($trim(payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-162&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag another &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and connect it to the last &lt;strong&gt;Change&lt;/strong&gt; node. Set &lt;code&gt;msg.payload&lt;/code&gt; to the following JSON object:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-168&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-168&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;capital&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; capital&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;population&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; population&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;area&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; area&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-168&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, drag a &lt;strong&gt;Join&lt;/strong&gt; node onto the canvas and connect it to the previous &lt;strong&gt;Change&lt;/strong&gt; node. This Join node will create an array of the objects we have created.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When you click the inject button again, you will see that the data is now structured and formatted. The output will contain objects with properties such as name, capital, population, and area. This data can now be displayed on the FlowFuse dashboard table. For more details, refer to the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-table.html&quot;&gt;FlowFuse table widget&lt;/a&gt;.&lt;/p&gt;
&lt;div id=&quot;nr-flow-191&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow191 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;cc3c919ad9f93cc6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;43ba04d623a8aa57&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d66b9fa2858cf5f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;html&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;outproperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tag&#92;&quot;:&#92;&quot;.country&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;as&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c4e9a4c8.487e68&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;43ba04d623a8aa57&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://www.scrapethissite.com/pages/simple/&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2d66b9fa2858cf5f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8e7b462a5b5a064e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-table&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;0c48f8d560157d3c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;maxrows&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;autocols&#92;&quot;:true,&#92;&quot;showSearch&#92;&quot;:true,&#92;&quot;selectionType&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;columns&#92;&quot;:[],&#92;&quot;mobileBreakpoint&#92;&quot;:&#92;&quot;sm&#92;&quot;,&#92;&quot;mobileBreakpointType&#92;&quot;:&#92;&quot;defaults&#92;&quot;,&#92;&quot;x&#92;&quot;:1870,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4e9a4c8.487e68&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Split Array&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1a1e8a0a.8e7b06&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a1e8a0a.8e7b06&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Extract Name&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;name&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$trim($split(payload, &#92;&#92;&#92;&quot;Capital: &#92;&#92;&#92;&quot;)[0])&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$split($split(payload, &#92;&#92;&#92;&quot;Capital: &#92;&#92;&#92;&quot;)[1], &#92;&#92;&#92;&quot;Population: &#92;&#92;&#92;&quot;)&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1000,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cfdb7c1f.9234b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cfdb7c1f.9234b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Extract Capital &amp;amp; Population&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;capital&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$trim(payload[0])&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$split(payload[1], &#92;&#92;&#92;&quot;Area (km2): &#92;&#92;&#92;&quot;)&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fb93f89b.b96138&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb93f89b.b96138&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Extract Population &amp;amp; Area&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;population&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$number($trim(payload[0]))&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;area&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$number($trim(payload[1]))&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{   &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: name,   &#92;&#92;&#92;&quot;capital&#92;&#92;&#92;&quot;: capital,   &#92;&#92;&#92;&quot;population&#92;&#92;&#92;&quot;: population,   &#92;&#92;&#92;&quot;area&#92;&#92;&#92;&quot;: area}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1510,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;342166ac8729e9d7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;342166ac8729e9d7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:true,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1710,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8e7b462a5b5a064e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c48f8d560157d3c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Group&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d0def7a91d3b7aa1&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0def7a91d3b7aa1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Page 1&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;c385dfc590b1308d&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/1&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;6be033291dd76b17&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:false,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;c385dfc590b1308d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-button&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;temporary&#92;&quot;,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;6be033291dd76b17&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#202c34&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#202c34&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;density&#92;&quot;:&#92;&quot;default&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow191.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-191&#39;) })&lt;/script&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Left side: Image showing the countries table we created on the FlowFuse dashboard. Right side: The original webpage with countries.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/webscrapping-result.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Left side: Image showing the table we created on the FlowFuse dashboard. Right side: The original webpage with countries.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;legal-and-ethical-considerations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#legal-and-ethical-considerations&quot;&gt;Legal and Ethical Considerations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web scraping can be a valuable tool for gathering data, but it&#39;s crucial to navigate the legal and ethical landscape responsibly. Adhere to websites&#39; terms of service, respect intellectual property and data privacy laws, and avoid actions that could disrupt a site&#39;s operation or misuse the scraped data. By staying informed and adhering to best practices, you can harness the power of web scraping tools like Node-RED while remaining ethically and legally compliant.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-scrape-web-data-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You’ve now learned to use Node-RED for web scraping, from sending requests and parsing HTML to transforming data into practical formats. This approach streamlines data collection from websites, making it easier to manage and analyze information efficiently.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/</id>
        <title>How to create and use Subflow in Node-RED</title>
        <summary>A Practical Guide to Implementing Subflows in Node-RED for Efficient Workflow Management</summary>
        <updated>2024-09-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In traditional programming, managing complex and repetitive tasks can quickly lead to a tangled mess of code that’s hard to maintain and update. To tackle this issue, developers use libraries or modules—reusable chunks of code that help organize functionality, minimize duplication, and keep codebases clean and manageable.&lt;/p&gt;
&lt;p&gt;Node-RED brings a similar solution to its visual programming environment with Subflows. Imagine Subflows as the visual counterpart to libraries. In this guide, we will explore what Subflows are, how to create them, and how to use them effectively to enhance your Node-RED experience.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-are-subflows%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#what-exactly-are-subflows%3F&quot;&gt;What Exactly Are Subflows?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing a Node-RED flow at the top selected for creating a Subflow, and the resulting Subflow at the bottom.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing a Node-RED flow at the top selected for creating a Subflow, and the resulting Subflow at the bottom.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Subflows in Node-RED are a way to group together a set of nodes and reusable flows into a single, reusable node. This helps you manage and organize complex workflows by encapsulating repetitive or complex logic into a modular unit. You can think of Subflows as custom nodes that you create and use within your flows to simplify your design and reduce redundancy.&lt;/p&gt;
&lt;h2 id=&quot;creating-a-subflow-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#creating-a-subflow-in-node-red&quot;&gt;Creating a Subflow in Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will create a Subflow for a flow that sends requests to an API and returns results. If the request faces an issue, it retries until it reaches the maximum retry limit. Let&#39;s assume we need to use this flow in multiple places, for different APIs, each with different retry timeouts. To avoid duplicating the flow logic, we can create a Subflow.&lt;/p&gt;
&lt;p&gt;To follow along, import the following flow into your Node-RED instance.&lt;/p&gt;
&lt;div id=&quot;nr-flow-192&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow192 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;132f4fdc40d55e89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:2840,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;612819f76617e5a8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:2840,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7e9e8e1af751bb92&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:1460,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8899fea497064b8c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4eca1de14599dd1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;delayv&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;milliseconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1900,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;96ca1ed69e7fa7ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96ca1ed69e7fa7ac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://jsonplaceholder.typicode.com/todos&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:2050,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f523bb034db360a4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3eb4ec6b71fc383b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;if success&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;statusCode&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;btwn&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;200&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;v2&#92;&quot;:&#92;&quot;299&#92;&quot;,&#92;&quot;v2t&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:2420,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;612819f76617e5a8&#92;&quot;],[&#92;&quot;bad4bdb7e00b7a80&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bad4bdb7e00b7a80&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;if max retries&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;retry_counter&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;gte&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;10000&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:2590,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;132f4fdc40d55e89&#92;&quot;],[&#92;&quot;b4eca1de14599dd1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8899fea497064b8c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry_interval&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;retry_counter&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1720,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4eca1de14599dd1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f523bb034db360a4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;retry_counter++&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry_counter+1&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2240,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3eb4ec6b71fc383b&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow192.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-192&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;creating-subflow-of-selection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#creating-subflow-of-selection&quot;&gt;Creating subflow of selection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing process of creating subflow from the selection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/selecting-and-converting-subflow.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing process of creating subflow from the selection&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the flow you want to convert into a Subflow.&lt;/li&gt;
&lt;li&gt;Open the main menu by clicking the top-right menu icon, and select &amp;quot;Selection to Subflow&amp;quot; under the Subflows option.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing subflow node added in the node palette&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/subflow-showing-in-pallete.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing subflow node added in the node palette&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once selected, the Subflow will be added to the node palette like other nodes. The selected flow will also be converted into a single node representing the Subflow.&lt;/p&gt;
&lt;h3 id=&quot;adding-properties-to-the-subflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#adding-properties-to-the-subflow&quot;&gt;Adding Properties to the Subflow&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Double-click on the Subflow, then click on &lt;strong&gt;&amp;quot;Edit Subflow template&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Editing the Subflow template by clicking on the &#39;Edit Subflow Template&#39; option.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-template-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Editing the Subflow template by clicking on the &#39;Edit Subflow Template&#39; option.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;A new flow tab for the Subflow will open. Click on &lt;strong&gt;&amp;quot;Edit Properties&amp;quot;&lt;/strong&gt; in the top-left corner.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The edit properties button for a Subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-properties.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The edit properties button for a Subflow&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;To add environment properties, click on the &lt;strong&gt;&amp;quot;+ add&amp;quot;&lt;/strong&gt; button located at the bottom-left.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The &#39;Add&#39; button for adding environment properties for subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-env.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The &#39;Add&#39; button for adding environment properties for subflow&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;In the field that opens, give the property a name and set its default value.&lt;/li&gt;
&lt;li&gt;Once you have added all your properties, you can view a preview by switching to the &lt;strong&gt;&amp;quot;UI PREVIEW&amp;quot;&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A preview of the Subflow environment properties&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-preivew-env.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;A preview of the Subflow environment properties&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click &amp;quot;Done&amp;quot; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;setting-added-environment-variables-in-the-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#setting-added-environment-variables-in-the-nodes&quot;&gt;Setting Added Environment Variables in the Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have added properties for the Subflow (which are environment variables), we need to use them in the relevant nodes, such as the HTTP request node, which will require an API and the max-retry setting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Double-click on the &lt;strong&gt;HTTP request&lt;/strong&gt; node, set the environment variable as &lt;code&gt;${your_env_name}&lt;/code&gt; into the URL feild, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The URL field of an HTTP request node in Node-RED with an environment variable added.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/http-request-url-env-adding.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The URL field of an HTTP request node in Node-RED with an environment variable added.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Next, double-click on the &lt;strong&gt;switch&lt;/strong&gt; node named &amp;quot;if max retries,&amp;quot; update the hardcoded max retry condition value to the environment variable you set for it, and click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The switch node in Node-RED with a max retry condition set using an environment variable.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/max-retry-setting.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;The switch node in Node-RED with a max retry condition set using an environment variable.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;managing-subflow-input-and-output-ports&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#managing-subflow-input-and-output-ports&quot;&gt;Managing Subflow Input and Output Ports&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we know, any node in Node-RED requires input and output ports to manage its data flow. Similarly, a Subflow node requires these ports to function correctly. In our Subflow example, it needs to be triggered and therefore requires at least one input port and one or more output ports. Specifically, our Subflow has two outputs: one for successfully fetched data and another to indicate when the maximum retry limit has been exceeded.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Subflow&lt;/strong&gt; tab, at the top, you will see an option for &lt;strong&gt;inputs&lt;/strong&gt; with values 0 and 1. Click on &lt;strong&gt;1&lt;/strong&gt; to add an input port (as a any Node-RED node can have only one input port). Once set to 1, you will see an input port added in the Subflow tab. Connect it to the appropriate node; in our example, it should be connected to the first &lt;strong&gt;change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Option to add input port for subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/input-adding-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Option to add input port for subflow&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Next, right after the &lt;strong&gt;inputs&lt;/strong&gt; option, you will see an option for &lt;strong&gt;outputs&lt;/strong&gt;. Unlike inputs, you can add as many outputs as you need. Once you&#39;ve added the outputs, connect them to the appropriate nodes. In our example, the first output should be connected to the first input of both &lt;strong&gt;switch&lt;/strong&gt; nodes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Option to add output ports for subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/output-adding-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Option to add output ports for subflow&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;adding-status-for-subflow-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#adding-status-for-subflow-nodes&quot;&gt;Adding Status for Subflow Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To effectively manage and monitor the execution of Subflows, you can add status indicators to your Subflow nodes. This allows you to see if the Subflow is functioning correctly and helps in debugging if something goes wrong. To add a status indicator:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Subflow flow tab at the top, click on the &lt;strong&gt;Status&lt;/strong&gt; node option to add a status node. This status node can be connected to the Node-RED status node to capture and display all statuses, or you can configure it to use &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Option to add status for subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/status-adding-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Option to add status for subflow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In our example, we need two indicators: one to display when the flow is retrying to request and another to indicate that the fetch operation has successfully completed.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag two &lt;strong&gt;Change&lt;/strong&gt; nodes onto the Canvas. Connect one Change node to the &lt;strong&gt;if success&lt;/strong&gt; switch node&#39;s first output and set the &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;&amp;quot;completed&amp;quot;&lt;/code&gt;. Connect the other Change node to the &lt;strong&gt;if max retries&lt;/strong&gt; switch node&#39;s first output and set its &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;&amp;quot;retrying&amp;quot;&lt;/code&gt;. Then, connect both Change nodes to the input of the Subflow status node.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;customizing-the-appearance-of-a-subflow-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#customizing-the-appearance-of-a-subflow-node&quot;&gt;Customizing the Appearance of a Subflow Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED allows you to customize the appearance of Subflow nodes, including setting the color, icon, port labels, and selecting the category in which it will be visible in the node palette.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Subflow flow tab, click on the &lt;strong&gt;&amp;quot;Edit Properties&amp;quot;&lt;/strong&gt; option in the top-left corner and switch to the &lt;strong&gt;&amp;quot;Appearance&amp;quot;&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the apperance tab of subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/customizing-apperance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the apperance tab of subflow&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Select a category from the available categories or add a new one by clicking on &lt;strong&gt;&amp;quot;Add new&amp;quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose a color for the Subflow node and select an icon.&lt;/li&gt;
&lt;li&gt;Provide labels for the ports so that when someone hovers over the Subflow input or output ports, they can quickly understand their purpose.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;adding-documentation-for-a-subflow-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#adding-documentation-for-a-subflow-node&quot;&gt;Adding Documentation for a Subflow Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED allows you to add documentation for Subflow nodes, providing guidance on how to use them. This documentation will be rendered in the help sidebar, similar to other nodes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Subflow flow tab, click on the &lt;strong&gt;&amp;quot;Edit Properties&amp;quot;&lt;/strong&gt; option in the top-left corner and switch to the &lt;strong&gt;&amp;quot;Description&amp;quot;&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the description tab of subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/documentation-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the apperance tab of subflow&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Enter the documentation content in markdown format that provides guidance on how to use the Subflow node effectively.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Done&lt;/strong&gt; to save.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once saved, the documentation will be displayed in the help sidebar when users click on the Subflow node in the Node-RED palette or hover over and select the help option for that node.&lt;/p&gt;
&lt;div id=&quot;nr-flow-193&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow193 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;subflow&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;API Retry &#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;## hee&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;in&#92;&quot;:[{&#92;&quot;x&#92;&quot;:50,&#92;&quot;y&#92;&quot;:30,&#92;&quot;wires&#92;&quot;:[{&#92;&quot;id&#92;&quot;:&#92;&quot;8899fea497064b8c&#92;&quot;}]}],&#92;&quot;out&#92;&quot;:[{&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[{&#92;&quot;id&#92;&quot;:&#92;&quot;3eb4ec6b71fc383b&#92;&quot;,&#92;&quot;port&#92;&quot;:0}]},{&#92;&quot;x&#92;&quot;:1610,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[{&#92;&quot;id&#92;&quot;:&#92;&quot;092547737a0cbee2&#92;&quot;,&#92;&quot;port&#92;&quot;:0}]}],&#92;&quot;env&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;URL&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;MAX_RETRY&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;}],&#92;&quot;meta&#92;&quot;:{},&#92;&quot;color&#92;&quot;:&#92;&quot;#D7D7A0&#92;&quot;,&#92;&quot;inputLabels&#92;&quot;:[&#92;&quot;Trigger&#92;&quot;],&#92;&quot;outputLabels&#92;&quot;:[&#92;&quot;API Response&#92;&quot;,&#92;&quot;Max Retry Exeeded&#92;&quot;],&#92;&quot;icon&#92;&quot;:&#92;&quot;node-red/white-globe.svg&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4eca1de14599dd1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;delayv&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;milliseconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;96ca1ed69e7fa7ac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;96ca1ed69e7fa7ac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;txt&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;${URL}&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f523bb034db360a4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3eb4ec6b71fc383b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;if success&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;statusCode&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;btwn&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;200&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;v2&#92;&quot;:&#92;&quot;299&#92;&quot;,&#92;&quot;v2t&#92;&quot;:&#92;&quot;num&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:920,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[],[&#92;&quot;bad4bdb7e00b7a80&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bad4bdb7e00b7a80&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;if max retries&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;retry_counter&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;gte&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;MAX_RETRY&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;env&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;092547737a0cbee2&#92;&quot;],[&#92;&quot;b4eca1de14599dd1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8899fea497064b8c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry_interval&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;retry_counter&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;num&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4eca1de14599dd1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f523bb034db360a4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;retry_counter++&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;retry_counter&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;retry_counter+1&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3eb4ec6b71fc383b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;092547737a0cbee2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ea5436b592a86b90&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;Max retry exeeded&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1360,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;132f4fdc40d55e89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:2420,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;612819f76617e5a8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:2420,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7e9e8e1af751bb92&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:1840,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ccadc2ba40bb8606&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ccadc2ba40bb8606&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;subflow:ea5436b592a86b90&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;380e37fed72e6885&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;URL&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;https://jsonplaceholder.typicode.com/photosS&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;name&#92;&quot;:&#92;&quot;MAX_RETRY&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;10000&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;x&#92;&quot;:2160,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;612819f76617e5a8&#92;&quot;],[&#92;&quot;132f4fdc40d55e89&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow193.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-193&#39;) })&lt;/script&gt;
&lt;p&gt;Now, just like regular Node-RED nodes, you can effectively use this Subflow node in your projects. With its added documentation, customized appearance, and status indicators, it integrates seamlessly into your Node-RED environment, enhancing both usability and functionality.&lt;/p&gt;
&lt;h3 id=&quot;benefits-of-using-subflows.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#benefits-of-using-subflows.&quot;&gt;Benefits of using subflows.&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modularity&lt;/strong&gt;: Subflows allow you to group related nodes into a single, reusable unit, making complex flows easier to manage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code Reuse&lt;/strong&gt;: They help avoid duplicating similar logic across different parts of your flow, saving time and effort.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplified Design&lt;/strong&gt;: Subflows can simplify your main flow by hiding complexity within a single node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier Maintenance&lt;/strong&gt;: Updating a Subflow automatically updates all instances where it is used, making maintenance quicker.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/09/how-to-use-subflow-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we explored the concept of subflows in Node-RED, including their definition and purpose. We walked through the steps to create and configure subflows, demonstrating how to integrate them into your main flow. Additionally, we discussed how to edit and update existing subflows, and provided best practices for managing and organizing them effectively.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/</id>
        <title>FlowFuse 2.8: Static File Service, LDAP Updates &amp; More</title>
        <summary>Let&#39;s take a look at the new features and improvements in FlowFuse 2.8</summary>
        <updated>2024-08-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.8 sees a new major feature introduced to the platform. The first iteration of the &amp;quot;Static Assets Service&amp;quot; is now available, allowing you to host and serve static files from your FlowFuse instance, giving you easy access to file storage for your applications, and seamless integration of those assets and files within Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;static-assets-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#static-assets-service&quot;&gt;Static Assets Service&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Static Assets Service allows you to host and serve static files from your FlowFuse instance. This feature is particularly useful for applications that require file storage, such as images, videos, or static data sets.&lt;/p&gt;
&lt;p&gt;With the Static Assets Service, you can upload files directly to your FlowFuse instance and access them from your Node-RED flows, like so:&lt;/p&gt;
&lt;video controls=&quot;&quot;&gt;
   &lt;source src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/Assets+Service+Demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
   Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;This is the first step in this new feature set, with more enhancements planned for future releases, whereby you&#39;ll also be able to configure access control to public HTTP endpoints for easy access in your Dashboards.&lt;/p&gt;
&lt;h2 id=&quot;ldap-service-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#ldap-service-improvements&quot;&gt;LDAP Service Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Team Membership in FlowFuse can now be automatically managed using LDAP groups. This means that you can now assign roles to LDAP groups, and when a user is added to that group in your LDAP server, they will automatically be assigned the respective role in FlowFuse.&lt;/p&gt;
&lt;p&gt;This also extends to the management of FlowFuse Admin users, which was previously only supported for SAML SSO.&lt;/p&gt;
&lt;p&gt;The Admin management feature is available for those running self-hosted FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;notifications-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#notifications-improvements&quot;&gt;Notifications Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last release we introduced the &lt;a href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release#notifications-inbox&quot;&gt;Notifications Inbox&lt;/a&gt;, and in this release we&#39;re starting to expand on the notifications that you wil receive in FlowFuse, starting with alerts when your Node-RED instances and devices crash unexpectedly, and when instances start in &amp;quot;Safe Mode&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing some example notifications to inform users of unexpected crashes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/2-8-release-notifications.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing some example notifications to inform users of unexpected crashes&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We&#39;re also added filters to show &amp;quot;Read&amp;quot; notifications, and grouping together similar notifications so that it&#39;s easy to parse if you have many notifications of the same type.&lt;/p&gt;
&lt;h2 id=&quot;managing-devices-at-scale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#managing-devices-at-scale&quot;&gt;Managing Devices at Scale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As promised in the &lt;a href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release#bulk-device-actions&quot;&gt;FlowFuse 2.7 Release&lt;/a&gt;, we&#39;ve expanded the actions you can take when working with many Devices at once, which now includes the ability to move Devices between Applications and Instances.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot to show the new &amp;quot;Move to Instance&amp;quot; and &amp;quot;Move to Application&amp;quot; bulk actions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/2-8-release-bulk-move.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot to show the new &amp;quot;Move to Instance&amp;quot; and &amp;quot;Move to Application&amp;quot; bulk actions&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;stricter-approach-to-expired-licenses&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#stricter-approach-to-expired-licenses&quot;&gt;Stricter Approach to Expired Licenses&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made some changes to how FlowFuse handles expired licenses for self-hosted users.&lt;/p&gt;
&lt;p&gt;If your license has expired, you will now be unable to access your FlowFuse instance until you renew your license. This is to ensure that you are always using the latest version of FlowFuse and have access to the latest features and security updates.&lt;/p&gt;
&lt;p&gt;If you are currently running an older version of FlowFuse with an expired license please &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact the Sales team&lt;/a&gt; to discuss renewing your license before upgrading to FlowFuse 2.8. You can check your current license on the &amp;quot;Admin Settings&amp;quot; &amp;gt; &amp;quot;Overview&amp;quot; page.&lt;/p&gt;
&lt;h2 id=&quot;and-much-more...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#and-much-more...&quot;&gt;And Much More...&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a full list of everything that went into our 2.8 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.8.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.8, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have an Enterprise license please make sure to review this &lt;a href=&quot;https://flowfuse.com/changelog/2024/08/enterprise-license-update/&quot;&gt;changelog entry&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-8-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/</id>
        <title>New Layout, Widget and Gauges Now Available in FlowFuse Dashboard</title>
        <summary>Our latest update for FlowFuse Dashboard introduces a new layout type, Tabs, a new widget, Number Input, and two fresh gauges, Battery and Tank Level, along with much more.</summary>
        <updated>2024-08-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;At FlowFuse, we&#39;re constantly evolving to make sure your dashboard experience is seamless and efficient. This month, we&#39;re excited to introduce several new features that enhance your interaction with the platform. From organizing your data with Tabs to visualizing critical information with new Gauges, we&#39;ve got you covered.&lt;/p&gt;
&lt;h2 id=&quot;new-layout%3A-tabs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#new-layout%3A-tabs&quot;&gt;New Layout: Tabs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We know that managing multiple data sources and visualizations can get overwhelming. To streamline your workflow, we&#39;ve introduced a new layout: Tabs.&lt;/p&gt;
&lt;p&gt;Tabs allow you to organize your widgets into separate, easily navigable sections, reducing clutter and making it easier to focus on specific datasets. Whether you&#39;re monitoring system performance, tracking KPIs, or managing IoT devices, Tabs will help you stay organized and efficient.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a tab layout in Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/layout-tab-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a tab layout in Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-widget%3A-number-input&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#new-widget%3A-number-input&quot;&gt;New Widget: Number Input&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Introducing the Number Input widget — a versatile addition that allows users to input numerical values directly into the dashboard. Whether you&#39;re setting thresholds, configuring parameters, or simply inputting data, this widget makes it easy to adjust values with precision. It’s ideal for use cases where user interaction with numerical data is required, such as controlling devices or updating settings in real time.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a number input widget with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-number-input-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a number input widget with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can try the Number Input now in our &lt;a href=&quot;https://dashboard-demos.flowfuse.cloud/dashboard/number-input&quot;&gt;live Dashboard running on FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-gauges&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#new-gauges&quot;&gt;New Gauges&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data visualization is a cornerstone of any effective dashboard. We’re excited to introduce two new gauges designed to provide at-a-glance insights into your key metrics.&lt;/p&gt;
&lt;h3 id=&quot;battery-charge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#battery-charge&quot;&gt;Battery Charge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Monitoring battery levels is crucial for applications that rely on mobile or remote devices. Our new Battery Gauge provides a clear visual representation of battery status, allowing you to quickly assess power levels and take action if necessary. It’s perfect for IoT deployments, mobile sensors, or any system where battery life is a key consideration.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a battery gauge with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-gauge-battery.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a battery gauge with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can try the Tank Level now in our &lt;a href=&quot;https://dashboard-demos.flowfuse.cloud/dashboard/gauge#battery-charge&quot;&gt;live Dashboard running on FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;tank-level&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#tank-level&quot;&gt;Tank Level&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Managing fluid levels in tanks is a common requirement across industries. The new Tank Level Gauge gives you a straightforward way to monitor liquid or gas levels in real time. Whether you&#39;re tracking water in a reservoir, fuel in a tank or any other fluid. this gauge provides the precision and clarity you need to maintain operational efficiency.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a partially filled tank level gauge with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-gauge-tank-filled.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a partially filled tank level gauge with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can try the Tank Level now in our &lt;a href=&quot;https://dashboard-demos.flowfuse.cloud/dashboard/gauge#tank-level&quot;&gt;live Dashboard running on FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can find the full 1.15.0 Release Notes &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v1.15.0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just to highlight a few, particularly valuable, updates and fixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Switch - Introduced an &amp;quot;Indicator&amp;quot; mode and enhanced memory handling for better performance.&lt;/li&gt;
&lt;li&gt;UI Table - Added a &amp;quot;Button&amp;quot; column type for improved interactivity.&lt;/li&gt;
&lt;li&gt;UI Button - Color customisation now available, without needing to write overriding CSS.&lt;/li&gt;
&lt;li&gt;Dynamic Properties - Added dynamic property support for &lt;code&gt;UI-Text-Input&lt;/code&gt; widget.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/dashboard-new-layout-widgets-and-gauges/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Work has already begun on the next release, &lt;code&gt;1.16.0&lt;/code&gt;, you can see what items we have queued up &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;here&lt;/a&gt;, if you&#39;ve got any feedback or suggestions, please do let us know, and feel free to open new issues on our &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/</id>
        <title>MQTT Sparkplug B Implementation: Protocol, Architecture &amp; Best Practices</title>
        <summary>Standardize and manage industrial IoT data with MQTT Sparkplug B</summary>
        <updated>2024-08-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Connected devices can generate a lot of data, but without a standardized format, managing and consuming it can be tricky. MQTT certainly simplifies getting your messages delivered but it does not enforce any structure. This is where MQTT Sparkplug B helps by providing a clear, standardized format for data. In this guide, we’ll show you how to use MQTT Sparkplug B with Node-RED to make managing your device data easier and more organized.&lt;/p&gt;
&lt;h2 id=&quot;what-is-mqtt-sparkplug%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#what-is-mqtt-sparkplug%3F&quot;&gt;What is MQTT Sparkplug?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT Sparkplug B is an open-source specification governed by the &lt;a href=&quot;https://www.eclipse.org/projects/efsp/&quot;&gt;Eclipse Foundation Specification Process (EFSP)&lt;/a&gt;. It defines a standardized MQTT topic namespace and payload format specifically designed for Industrial IoT (IIoT), with particular focus on real-time &lt;a href=&quot;https://flowfuse.com/solutions/scada/&quot;&gt;SCADA&lt;/a&gt;, control systems, and &lt;a href=&quot;https://flowfuse.com/blog/2025/11/building-hmi-for-equipment-control/&quot;&gt;HMI&lt;/a&gt; solutions.&lt;/p&gt;
&lt;p&gt;At its core, Sparkplug B extends MQTT 3.1.1 by adding structured topic namespace conventions, Google Protocol Buffer encoded payloads, state-aware birth and death certificates, metric aliasing for bandwidth optimization, and store-and-forward capabilities for intermittent connectivity. These additions transform MQTT from a simple messaging protocol into a complete industrial communication framework.&lt;/p&gt;
&lt;h3 id=&quot;the-industrial-integration-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#the-industrial-integration-problem&quot;&gt;The Industrial Integration Problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In typical factory environments, every machine manufacturer implements MQTT differently. Consider a real-world scenario where Machine A publishes temperature data to &lt;code&gt;factory/line1/temp&lt;/code&gt; with a JSON payload containing the temperature value. Meanwhile, Machine B sends its data to &lt;code&gt;sensors/machineB/env&lt;/code&gt; with a completely different JSON structure that includes both temperature and timestamp. Machine C takes yet another approach, publishing raw numeric values to &lt;code&gt;data/mc/status&lt;/code&gt; with no context or metadata.&lt;/p&gt;
&lt;p&gt;Each device requires custom parsing logic, error handling, and documentation. Integration complexity grows exponentially with each new device type. Your development team spends weeks building and maintaining custom parsers instead of focusing on business logic.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Manufacturing dashboard struggling with non-standardized MQTT data from multiple sources&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/with-plane-mqtt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Dashboard complexity increases exponentially without standardized data formats&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With Sparkplug B standardization, all devices publish to structured topics following the format &lt;code&gt;spBv1.0/Factory/DDATA/Line1/MachineA&lt;/code&gt; with consistent Protocol Buffer payloads. Each message contains typed metrics, timestamps, and quality indicators. Integration becomes predictable and maintainable. When you add a new device, it automatically describes its capabilities through birth certificates, eliminating the need for custom integration code.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Manufacturing dashboard efficiently processing standardized Sparkplug B data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/with-sparkplug.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Standardized format enables reliable data aggregation across heterogeneous devices&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;sparkplug-b-architecture-patterns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#sparkplug-b-architecture-patterns&quot;&gt;Sparkplug B Architecture Patterns&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Several architectural patterns have emerged from production Sparkplug B deployments. Understanding these patterns helps you design scalable, maintainable systems.&lt;/p&gt;
&lt;h3 id=&quot;edge-node-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#edge-node-architecture&quot;&gt;Edge Node Architecture&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The edge node serves as the gateway between physical devices and the MQTT broker. A single edge node typically manages multiple devices, publishing aggregate birth certificates and handling communication for all attached devices. This centralized approach simplifies device management and reduces broker connections.&lt;/p&gt;
&lt;p&gt;Edge nodes implement store-and-forward buffering to handle temporary connectivity loss. When the broker becomes unreachable, the edge node buffers data locally. After reconnection, it publishes buffered data with historical flags set, allowing applications to distinguish between real-time and historical data.&lt;/p&gt;
&lt;p&gt;The edge node monitors broker connectivity and automatically publishes &lt;code&gt;NBIRTH&lt;/code&gt; after reconnection. It manages sequence numbers across all messages from its devices, enabling applications to detect lost messages. Many edge nodes implement local data processing, filtering, and aggregation before publishing to reduce bandwidth and broker load.&lt;/p&gt;
&lt;h3 id=&quot;primary-application-pattern&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#primary-application-pattern&quot;&gt;Primary Application Pattern&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The primary application concept allows edge nodes to adapt their behavior based on application state. A designated primary application publishes STATE messages indicating its operational status. Edge nodes subscribe to these STATE messages and adjust their reporting frequency or metrics based on whether the primary application is online.&lt;/p&gt;
&lt;p&gt;For example, an edge node might publish data every second when the primary SCADA application is connected but reduce to every 60 seconds when no primary application is available. This adaptive behavior conserves bandwidth and broker resources while ensuring data availability when needed.&lt;/p&gt;
&lt;h3 id=&quot;command-and-control-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#command-and-control-flow&quot;&gt;Command and Control Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sparkplug B enables bidirectional communication through &lt;code&gt;NCMD&lt;/code&gt; and &lt;code&gt;DCMD&lt;/code&gt; messages. Applications publish commands to specific topics, and edge nodes or devices execute the commands and respond with updated metric values in &lt;code&gt;NDATA&lt;/code&gt; or &lt;code&gt;DDATA&lt;/code&gt; messages.&lt;/p&gt;
&lt;p&gt;Command messages use the same Protocol Buffer format as data messages but flow in the opposite direction. Applications might send a write command to change a setpoint, a rebirth command to request fresh birth certificates, or a custom command to trigger device-specific actions. The standardized command structure enables generic control applications that work with any Sparkplug-compliant device.&lt;/p&gt;
&lt;h2 id=&quot;the-mqtt-sparkplug-specification-for-iiot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#the-mqtt-sparkplug-specification-for-iiot&quot;&gt;The MQTT Sparkplug Specification for IIoT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have an overview of Sparkplug B and its role in standardizing data formats, it’s time to dive deeper into how this protocol structures its payloads and topics. Understanding these details will give you insight into how Sparkplug B efficiently manages data in complex industrial environments and will assist you in implementing it effectively in your own projects.&lt;/p&gt;
&lt;p&gt;Sparkplug B utilizes Google Protocol Buffers (Protobufs) for encoding its messages. Protobufs offer a compact and fast way to serialize structured data, preserving MQTT&#39;s lightweight nature while introducing a robust framework for handling complex data.&lt;/p&gt;
&lt;h3 id=&quot;the-mqtt-sparkplug-specification-for-iiot-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#the-mqtt-sparkplug-specification-for-iiot-1&quot;&gt;The MQTT Sparkplug Specification for IIoT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Sparkplug B specification addresses critical industrial requirements that standard MQTT implementations typically handle inconsistently. The specification is built around several core concepts that work together to create a robust industrial messaging framework.&lt;/p&gt;
&lt;h3 id=&quot;topic-namespace-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#topic-namespace-architecture&quot;&gt;Topic Namespace Architecture&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sparkplug B enforces a hierarchical topic namespace that follows a specific pattern: &lt;code&gt;spBv1.0/{group_id}/{message_type}/{edge_node_id}/{device_id}&lt;/code&gt;. The namespace starts with the protocol version identifier &lt;code&gt;spBv1.0&lt;/code&gt;, ensuring clients can identify Sparkplug messages. The group_id provides logical grouping such as factory, building, or region. The message_type specifies whether this is a birth certificate, data update, death notification, or command. The edge_node_id identifies the gateway or edge node, and optionally, a device_id can specify individual devices under that edge node.&lt;/p&gt;
&lt;p&gt;For example, a temperature sensor in a manufacturing facility might publish to &lt;code&gt;spBv1.0/Manufacturing/DDATA/Gateway01/TempSensor05&lt;/code&gt;. This structured approach eliminates ambiguity and enables automatic topic subscription patterns.&lt;/p&gt;
&lt;h3 id=&quot;protocol-buffer-payloads&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#protocol-buffer-payloads&quot;&gt;Protocol Buffer Payloads&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rather than using JSON or other text-based formats, Sparkplug B employs &lt;a href=&quot;https://flowfuse.com/blog/2025/12/node-red-buffer-parser-industrial-data/&quot;&gt;Google Protocol Buffers&lt;/a&gt; for message encoding. This choice delivers several advantages in industrial environments. The compact binary format produces significantly smaller messages than JSON, reducing bandwidth consumption on constrained networks. Protocol Buffers provide strongly typed data fields, eliminating parsing ambiguities. The format supports backward compatibility, allowing older clients to work with newer message versions. Finally, efficient parsing performance matters when handling thousands of messages per second.&lt;/p&gt;
&lt;h3 id=&quot;state-management-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#state-management-system&quot;&gt;State Management System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The specification includes explicit state awareness through birth and death certificates. When an edge node or device connects to the broker, it publishes a birth certificate (&lt;code&gt;NBIRTH&lt;/code&gt; for nodes, &lt;code&gt;DBIRTH&lt;/code&gt; for devices) that declares all available metrics, their data types, and initial values. This self-description capability means applications can discover device capabilities automatically without external configuration files.&lt;/p&gt;
&lt;p&gt;When devices disconnect, either gracefully or due to network failure, death certificates (&lt;code&gt;NDEATH&lt;/code&gt;/&lt;code&gt;DDEATH&lt;/code&gt;) signal the disconnection to all subscribers. The MQTT Last Will and Testament feature ensures death certificates publish even when devices lose connectivity unexpectedly. Sequence numbers in every message enable detection of lost messages, while timestamps provide temporal context for all data points.&lt;/p&gt;
&lt;h3 id=&quot;metric-definition-framework&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#metric-definition-framework&quot;&gt;Metric Definition Framework&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each metric in Sparkplug B carries comprehensive metadata beyond just a name and value. The specification supports a wide range of data types including various integer sizes (Int8 through Int64, both signed and unsigned), floating-point numbers (Float and Double), Boolean values, strings, timestamps, UUIDs, binary data, and complex structures like datasets and templates.&lt;/p&gt;
&lt;p&gt;Every metric includes a timestamp indicating when the value was captured, not just when it was transmitted. Quality flags indicate whether data is historical (stored and forwarded), transient (not to be stored), or null (sensor failure). This rich metadata enables applications to make informed decisions about data processing and storage.&lt;/p&gt;
&lt;h3 id=&quot;message-types-and-their-purposes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#message-types-and-their-purposes&quot;&gt;Message Types and Their Purposes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sparkplug B defines specific message types for different communication needs. &lt;code&gt;NBIRTH&lt;/code&gt; messages announce edge node connection and available metrics. &lt;code&gt;NDATA&lt;/code&gt; messages carry periodic metric updates from edge nodes. &lt;code&gt;NDEATH&lt;/code&gt; messages signal edge node disconnection. &lt;code&gt;DBIRTH&lt;/code&gt;, &lt;code&gt;DDATA&lt;/code&gt;, and &lt;code&gt;DDEATH&lt;/code&gt; provide the same functions for devices under edge nodes.&lt;code&gt;NCMD&lt;/code&gt; and &lt;code&gt;DCMD&lt;/code&gt; enable command and control, allowing applications to send instructions to nodes and devices. STATE messages, published by primary applications, indicate application health and readiness.&lt;/p&gt;
&lt;h2 id=&quot;sparkplug-b-vs-plain-mqtt%3A-understanding-the-differences&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#sparkplug-b-vs-plain-mqtt%3A-understanding-the-differences&quot;&gt;Sparkplug B vs Plain MQTT: Understanding the Differences&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While both &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;plain MQTT&lt;/a&gt; and Sparkplug B use the same MQTT transport protocol, they solve &lt;strong&gt;very different problems&lt;/strong&gt;.
Plain MQTT focuses on moving messages reliably, whereas Sparkplug B defines &lt;strong&gt;how industrial data should be structured, identified, and managed&lt;/strong&gt; across devices and applications.&lt;/p&gt;
&lt;p&gt;The table below highlights the practical differences that matter when designing real-world IIoT and SCADA systems.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Plain MQTT&lt;/th&gt;
&lt;th&gt;MQTT Sparkplug B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What it is&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Messaging protocol&lt;/td&gt;
&lt;td&gt;Industrial IoT specification built on MQTT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Message transport&lt;/td&gt;
&lt;td&gt;Standardized industrial data exchange&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Topic structure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fully custom, no enforced rules&lt;/td&gt;
&lt;td&gt;Strict, standardized namespace (&lt;code&gt;spBv1.0/...&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Payload format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JSON, text, or custom binary&lt;/td&gt;
&lt;td&gt;Google Protocol Buffers (binary, compact)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Payload consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Varies by device and vendor&lt;/td&gt;
&lt;td&gt;Guaranteed consistent structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data typing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not enforced&lt;/td&gt;
&lt;td&gt;Strongly typed metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Device discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual configuration&lt;/td&gt;
&lt;td&gt;Automatic via NBIRTH / DBIRTH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State awareness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited (LWT only)&lt;/td&gt;
&lt;td&gt;Full lifecycle (BIRTH, DATA, DEATH)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Message loss detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Sequence numbers included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional, application-defined&lt;/td&gt;
&lt;td&gt;Mandatory per metric&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data quality flags&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom implementation&lt;/td&gt;
&lt;td&gt;Built-in (historical, transient, null)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bandwidth efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower (JSON overhead)&lt;/td&gt;
&lt;td&gt;Higher (protobuf + metric aliasing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metric aliasing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Command &amp;amp; control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom topics and logic&lt;/td&gt;
&lt;td&gt;Standardized NCMD / DCMD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interoperability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low (vendor-specific)&lt;/td&gt;
&lt;td&gt;High (vendor-neutral)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Human readability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low (binary encoded)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debugging effort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy with basic tools&lt;/td&gt;
&lt;td&gt;Requires Sparkplug-aware tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on custom design&lt;/td&gt;
&lt;td&gt;Designed for large-scale IIoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MQTT-level (TLS, ACLs)&lt;/td&gt;
&lt;td&gt;MQTT-level (same as plain MQTT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium to high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best fit use cases&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small systems, prototypes, simple sensors&lt;/td&gt;
&lt;td&gt;SCADA, HMI, multi-vendor industrial systems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;using-mqtt-sparkplug-b-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#using-mqtt-sparkplug-b-with-node-red&quot;&gt;Using MQTT Sparkplug B with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we understand what Sparkplug B is and how it structures industrial data, let’s see how to use it in practice with Node-RED.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; is a popular low-code tool for building IoT and industrial data flows. It’s widely used at the edge to connect devices, process data, and integrate with MQTT brokers. With dedicated Sparkplug nodes, Node-RED makes it easy to publish and consume Sparkplug B messages without manually handling topics, protobufs, or state management.&lt;/p&gt;
&lt;p&gt;To run Node-RED reliably in production—especially for industrial and edge deployments, &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; provides a managed platform for deploying, scaling, and managing Node-RED instances. FlowFuse also includes a built-in MQTT broker, making it simple to get started with Sparkplug B without additional infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Create a free FlowFuse account&lt;/a&gt; to deploy Node-RED, connect devices, and start working with MQTT Sparkplug B in minutes.&lt;/p&gt;
&lt;p&gt;In the following example, we’ll configure a Node-RED flow where a factory machine publishes temperature and humidity data using Sparkplug B, and then consumes that data downstream.&lt;/p&gt;
&lt;h3 id=&quot;prerequisite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#prerequisite&quot;&gt;Prerequisite&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;node-red-contrib-mqtt-sparkplug-plus: Install this &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-mqtt-sparkplug-plus&quot;&gt;Node-RED package for Sparkplug B&lt;/a&gt; support via palette manager.&lt;/li&gt;
&lt;li&gt;MQTT Broker: An MQTT broker is required to send and receive data between clients. If you do not already have one, FlowFuse offers a built-in MQTT broker service that simplifies the process of using MQTT with Node-RED—no external setup required. To learn how to use the FlowFuse MQTT Broker and create and manage clients, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/teambroker/&quot;&gt;FlowFuse MQTT documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;configuring-node-red-for-mqtt-sparkplug-b&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#configuring-node-red-for-mqtt-sparkplug-b&quot;&gt;Configuring Node-RED for MQTT Sparkplug B&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag any mqtt sparkplug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the mqtt sparkplug node to open the configuration panel.&lt;/li&gt;
&lt;li&gt;Click the &amp;quot;+&amp;quot; icon next to the &amp;quot;Broker&amp;quot; field. Enter your MQTT broker&#39;s host address (e.g., &lt;code&gt;broker.flowfuse.cloud&lt;/code&gt;), specify the port number (e.g., &lt;code&gt;1883&lt;/code&gt; for unencrypted or &lt;code&gt;8883&lt;/code&gt; for TLS), and configure the TLS settings if required. Enter the username and password, enter a Client ID, Set the &amp;quot;Keep Alive&amp;quot; interval (default is 60 seconds).&lt;/li&gt;
&lt;li&gt;Switch to the Sparkplug tab by clicking the Sparkplug option in the top-right corner.&lt;/li&gt;
&lt;li&gt;Enter a name in the &amp;quot;Name&amp;quot; field (this will be the Edge Node ID). Enter the group name in the &amp;quot;Group&amp;quot; field. Select &amp;quot;No&amp;quot; for the compression setting. Enable the &amp;quot;Use Alias for Metrics&amp;quot; option if you prefer not to send the full metric names every time and use aliases instead.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Add&amp;quot; to save the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the configuration of Sparkplug broker config node&quot; alt=&quot;Screenshot showing the configuration of Sparkplug broker config node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot showing the configuration of Sparkplug broker config node&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;sending-data-to-mqtt-with-sparkplug-b&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#sending-data-to-mqtt-with-sparkplug-b&quot;&gt;Sending Data to MQTT with Sparkplug B&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Drag the inject node onto the canvas. Set the &lt;code&gt;msg.payload&lt;/code&gt; to the metrics you want to send and set the repeat interval according to your preference. This inject node could be any node that triggers the data sending. For testing purpose, you can use the following JSONata expression to simulate temperature and humidly metrics:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-459&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-459&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;metrics&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor/temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $random() * &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sensor/humidity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $random() * &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-459&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Drag the mqtt sparkplug device node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-click the mqtt sparkplug device node to open the configuration panel. Add the metric names that you will be sending by clicking the bottom-left &amp;quot;Add&amp;quot; button. Ensure that the names match the metric names in the payload you are sending and specify the data types for each metric.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Sparkplug Device node configuration and the &#39;Add&#39; button for defining metrics&quot; alt=&quot;Screenshot showing the Sparkplug Device node configuration and the &amp;quot;Add&amp;quot; button for defining metrics&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-sparkplug-device-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot showing the Sparkplug Device node configuration and the &amp;quot;Add&amp;quot; button for defining metrics&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Switch to the Advanced tab by clicking the &amp;quot;Advanced&amp;quot; option at the top-right.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable the &amp;quot;Send Birth Immediately&amp;quot; option. This ensures that a Birth message (DBIRTH) is sent immediately upon deployment and connection to the MQTT broker. Note that enabling this option will send the &lt;code&gt;DBIRTH&lt;/code&gt; message when the device node connects, but an &lt;code&gt;NBIRTH&lt;/code&gt; message will be sent successful connection of mqtt sparkplug out node if you are using.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Sparkplug Device node configuration and the &#39;Add&#39; button for defining metrics&quot; alt=&quot;Screenshot showing the Sparkplug Device node configuration and the &amp;quot;Add&amp;quot; button for defining metrics&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-spark-device-advance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot showing the Sparkplug Device node configuration and the &amp;quot;Add&amp;quot; button for defining metrics&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Optionally, enable Store and Forward when not connected to ensure that messages are stored and sent once the connection is re-established. To use this option, make sure you have enabled it in the mqtt sparkplug broker config node and specified the destination.&lt;/li&gt;
&lt;li&gt;Connect the inject node&#39;s output to the mqtt sparkplug device node&#39;s input.&lt;/li&gt;
&lt;li&gt;Deploy the flow by clicking the top-right &amp;quot;Deploy&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you deploy the flow and all devices connect to the MQTT broker, the system automatically send a &lt;code&gt;DBIRTH&lt;/code&gt; message as soon as each device within the node connects, signalling that the device is ready for data transmission.&lt;/p&gt;
&lt;div id=&quot;nr-flow-147&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow147 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;f2864f2b830e3590&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt sparkplug device&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine1&#92;&quot;,&#92;&quot;metrics&#92;&quot;:{&#92;&quot;sensor/temperature&#92;&quot;:{&#92;&quot;dataType&#92;&quot;:&#92;&quot;Float&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;sensor/temperature&#92;&quot;},&#92;&quot;sensor/humidity&#92;&quot;:{&#92;&quot;dataType&#92;&quot;:&#92;&quot;Float&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;sensor/humidity&#92;&quot;}},&#92;&quot;broker&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;birthImmediately&#92;&quot;:true,&#92;&quot;bufferDevice&#92;&quot;:false,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3dfc9b74f5e36bec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;90cc413f58871fc1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send Metrics&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;{    &#92;&#92;&#92;&quot;metrics&#92;&#92;&#92;&quot;: [        {            &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;sensor/temperature&#92;&#92;&#92;&quot;,            &#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;: $random()*100        },        {            &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;sensor/humidity&#92;&#92;&#92;&quot;,            &#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;: $random()*100        }    ]}&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:130,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2864f2b830e3590&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3dfc9b74f5e36bec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-sparkplug-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Local Host&#92;&quot;,&#92;&quot;deviceGroup&#92;&quot;:&#92;&quot;My Devices&#92;&quot;,&#92;&quot;eonName&#92;&quot;:&#92;&quot;Node-Red&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;localhost&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;enableStoreForward&#92;&quot;:false,&#92;&quot;compressAlgorithm&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;aliasMetrics&#92;&quot;:true,&#92;&quot;manualEoNBirth&#92;&quot;:false,&#92;&quot;primaryScada&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow147.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-147&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;receiving-data-from-mqtt-with-sparkplug-b&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#receiving-data-from-mqtt-with-sparkplug-b&quot;&gt;Receiving Data from MQTT with Sparkplug B&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag the mqtt sparkplug in node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the node and configure the broker settings.&lt;/li&gt;
&lt;li&gt;Enter the topic in the &amp;quot;Topic&amp;quot; field in the format &lt;code&gt;namespace/group_id/message_type/edge_node_id/[device_id]&lt;/code&gt;. Use &lt;code&gt;DDATA&lt;/code&gt; for receiving metrics you are sending using device node or a wildcard like &lt;code&gt;spBv1.0/group_id/+/+/[device_id]&lt;/code&gt; to listen to all message types from a specific device.&lt;/li&gt;
&lt;li&gt;Select the desired &amp;quot;QoS&amp;quot; level.&lt;/li&gt;
&lt;li&gt;Drag a debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the mqtt sparkplug in node’s output to the debug node’s input.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Deploy&amp;quot; to save and run the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you will be able to see the &lt;code&gt;DBIRTH&lt;/code&gt;, and &lt;code&gt;DDATA&lt;/code&gt; messages printed on the debug panel.&lt;/p&gt;
&lt;div id=&quot;nr-flow-148&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow148 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a98c49d80bb5c4ee&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt sparkplug in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;spBv1.0/My Devices/DDATA/Node-RED/Machine1&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;655761fb21409216&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;655761fb21409216&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-sparkplug-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Local Host&#92;&quot;,&#92;&quot;deviceGroup&#92;&quot;:&#92;&quot;My Devices&#92;&quot;,&#92;&quot;eonName&#92;&quot;:&#92;&quot;Node-Red&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;localhost&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;enableStoreForward&#92;&quot;:false,&#92;&quot;compressAlgorithm&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;aliasMetrics&#92;&quot;:true,&#92;&quot;manualEoNBirth&#92;&quot;:false,&#92;&quot;primaryScada&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow148.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-148&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;sending-commands-for-devices-and-eon-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#sending-commands-for-devices-and-eon-nodes&quot;&gt;Sending Commands for devices and EoN nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Beyond data exchange, MQTT Sparkplug B allows you to send commands for managing devices and Edge of Network (EoN) nodes, such as initiating a device&#39;s rebirth or signalling its death.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;msg.command&lt;/code&gt; in the inject node to the desired command. For instance, you can use the following JSON object to send a command that triggers a device&#39;s death:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-573&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-573&quot; class=&quot;language-json&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;device&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;death&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;   &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-573&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, to send a command that triggers a device&#39;s rebirth, use:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-577&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-577&quot; class=&quot;language-json&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;device&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;rebirth&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;   &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-577&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the output of the inject node to the input of the relevant mqtt sparkplug device node.&lt;/li&gt;
&lt;li&gt;Deploy the flow by clicking the Deploy button at the top-right of the Node-RED interface.&lt;/li&gt;
&lt;li&gt;Click the inject node’s button to send the command.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In this example, we&#39;ve used an inject node to manually send commands, but you can also trigger these commands based on other inputs or conditions within your flow, such as device status or sensor data. For more information on available commands and advanced configurations, refer to the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-mqtt-sparkplug-plus&quot;&gt;MQTT Sparkplug nodes documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div id=&quot;nr-flow-149&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow149 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;f2864f2b830e3590&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt sparkplug device&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine1&#92;&quot;,&#92;&quot;metrics&#92;&quot;:{&#92;&quot;sensor/temperature&#92;&quot;:{&#92;&quot;dataType&#92;&quot;:&#92;&quot;Float&#92;&quot;},&#92;&quot;sensor/humidity&#92;&quot;:{&#92;&quot;dataType&#92;&quot;:&#92;&quot;Float&#92;&quot;}},&#92;&quot;broker&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;birthImmediately&#92;&quot;:true,&#92;&quot;bufferDevice&#92;&quot;:false,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3dfc9b74f5e36bec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;90cc413f58871fc1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send connect command&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;node&#92;&#92;&#92;&quot;:{&#92;&#92;&#92;&quot;connect&#92;&#92;&#92;&quot;:true}}&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2864f2b830e3590&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3dfc9b74f5e36bec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;915ca0772eebee04&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send rebirth command&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;device&#92;&#92;&#92;&quot;:{&#92;&#92;&#92;&quot;rebirth&#92;&#92;&#92;&quot;:true}}&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2864f2b830e3590&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;696db58cc9eb029d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;239c9025714089d3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send death command&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;command&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;device&#92;&#92;&#92;&quot;:{&#92;&#92;&#92;&quot;death&#92;&#92;&#92;&quot;:true}}&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2864f2b830e3590&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-sparkplug-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Local Host&#92;&quot;,&#92;&quot;deviceGroup&#92;&quot;:&#92;&quot;My Devices&#92;&quot;,&#92;&quot;eonName&#92;&quot;:&#92;&quot;Node-Red&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;localhost&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;enableStoreForward&#92;&quot;:false,&#92;&quot;compressAlgorithm&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;aliasMetrics&#92;&quot;:true,&#92;&quot;manualEoNBirth&#92;&quot;:true,&#92;&quot;primaryScada&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow149.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-149&#39;) })&lt;/script&gt;
&lt;p&gt;If you need more flexibility in defining topic names when sending data, you can use the mqtt sparkplug out node. It’s quite similar to the standard mqtt out node but is designed to handle Sparkplug-encoded messages. Below is an example showing how to use the mqtt sparkplug out node with in nodes.&lt;/p&gt;
&lt;div id=&quot;nr-flow-150&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow150 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;bbe3765e67eed956&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt sparkplug in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f098830cc10afc2f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;spBv1.0/+/+/#&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d45ff4446380beaa&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3b2b9788c51d5c3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt sparkplug out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f098830cc10afc2f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;spBv1.0/My Devices/NDATA/Node-Red&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retain&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d45ff4446380beaa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f098830cc10afc2f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dc73048fd385783a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;f098830cc10afc2f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send Metrics&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;{    &#92;&#92;&#92;&quot;metrics&#92;&#92;&#92;&quot;: [        {            &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;sensor/temperature&#92;&#92;&#92;&quot;,            &#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;: $random(),            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Float&#92;&#92;&#92;&quot;        },        {            &#92;&#92;&#92;&quot;name&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;sensor/humidity&#92;&#92;&#92;&quot;,            &#92;&#92;&#92;&quot;value&#92;&#92;&#92;&quot;: $random(),            &#92;&#92;&#92;&quot;type&#92;&#92;&#92;&quot;: &#92;&#92;&#92;&quot;Float&#92;&#92;&#92;&quot;        }    ]}&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3b2b9788c51d5c3b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0d831bd9ba588536&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-sparkplug-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Local Host&#92;&quot;,&#92;&quot;deviceGroup&#92;&quot;:&#92;&quot;My Devices&#92;&quot;,&#92;&quot;eonName&#92;&quot;:&#92;&quot;Node-Red&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;localhost&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;enableStoreForward&#92;&quot;:false,&#92;&quot;compressAlgorithm&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;aliasMetrics&#92;&quot;:true,&#92;&quot;manualEoNBirth&#92;&quot;:false,&#92;&quot;primaryScada&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow150.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-150&#39;) })&lt;/script&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Images of some Sparkplug messages printed on debug panel&quot; alt=&quot;&amp;quot;Images of some Sparkplug messages printed on debug panel&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sparkplug-messages.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Images of some Sparkplug messages printed on debug panel&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;best-practices-for-production-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#best-practices-for-production-deployments&quot;&gt;Best Practices for Production Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Getting Sparkplug B working is only the first step. Running it reliably in production means thinking about naming, state, performance, and failure handling from day one. The best practices below focus on the things that matter most once your system is live—keeping data trustworthy, networks efficient, and recovery predictable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Name things like you mean it&lt;/strong&gt;
Use clear group, edge, and device names that match your factory or system layout. Future you will thank you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Birth messages are non-negotiable&lt;/strong&gt;
Always send &lt;code&gt;NBIRTH&lt;/code&gt; and &lt;code&gt;DBIRTH&lt;/code&gt; on start and reconnect. If apps don’t see a birth, they don’t trust the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alias your metrics&lt;/strong&gt;
Turn on metric aliasing to cut payload size and keep networks fast and efficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Listen for Death messages&lt;/strong&gt;
&lt;code&gt;NDEATH&lt;/code&gt; and &lt;code&gt;DDEATH&lt;/code&gt; are early warning signals. Use them to detect failures instantly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Buffer with intent&lt;/strong&gt;
Store-and-forward is great for flaky networks—just don’t let backlogs pile up unchecked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lock down MQTT early&lt;/strong&gt;
Use TLS, authentication, and topic permissions from day one. Security is easier before go-live.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Break it on purpose&lt;/strong&gt;
Restart brokers and edge nodes during testing. A system that recovers cleanly is production-ready.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/using-mqtt-sparkplugb-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MQTT Sparkplug B transforms MQTT from a simple messaging protocol into a robust, standardized framework for industrial IoT. By enforcing structured topics, typed metrics, state awareness, and efficient payloads, it makes integrating heterogeneous devices predictable, scalable, and reliable.&lt;/p&gt;
&lt;p&gt;Following best practices—clear naming, birth/death messages, metric aliasing, buffering, security, and deliberate testing—ensures your system runs smoothly in production and avoids costly downtime.&lt;/p&gt;
&lt;p&gt;For teams looking to get Sparkplug B up and running quickly, &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;FlowFuse&lt;/a&gt; provides a production-ready, easy-to-use platform. With minimal setup and no advanced skills required, you can deploy, scale, and monitor industrial flows in minutes. Start building your reliable, standardized IIoT solution today.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/</id>
        <title>Monitoring and Optimizing Node-RED Flows with Open Telemetry.</title>
        <summary>Integrating Open Telemetry with Node-RED for Efficient Distributed Tracing</summary>
        <updated>2024-08-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever found yourself frustrated by unexpected delays in your Node-RED flows, wondering where the bottlenecks are hiding? Even small latency issues can have a big impact on your system&#39;s performance. That&#39;s where Open Telemetry comes in. With its powerful distributed tracing capabilities, you can finally take control and get a clear view of how your flows are performing in real time.&lt;/p&gt;
&lt;p&gt;Integrating Open Telemetry with Node-RED allows you to monitor latency across your flows. By implementing distributed tracing, you’ll gain the ability to see exactly where delays occur, helping you optimize performance and ensure your IoT applications run efficiently.&lt;/p&gt;
&lt;h2 id=&quot;what-is-distributed-tracing-and-how-does-open-telemetry-help%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#what-is-distributed-tracing-and-how-does-open-telemetry-help%3F&quot;&gt;What is Distributed Tracing and How Does Open Telemetry Help?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Distributed tracing is a method used to track and observe the flow of requests through different services within a distributed system. It provides insights into how requests are handled, where delays occur, and how different components interact. By visualizing the path of a request across your system, distributed tracing helps you identify performance bottlenecks and optimize the overall efficiency of your applications.&lt;/p&gt;
&lt;h3 id=&quot;what-is-opentelemetry%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#what-is-opentelemetry%3F&quot;&gt;What is OpenTelemetry?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Open Telemetry is an open-source framework designed to help you monitor and understand your software systems. It collects and organizes data on how your applications perform and behave, allowing you to track requests as they move through various services. Open Telemetry provides a standardized way to gather and analyze telemetry data, including traces, metrics, and logs, to give you a comprehensive view of your system’s performance.&lt;/p&gt;
&lt;p&gt;In Node-RED The Open Telemetry module helps track messages by creating &amp;quot;spans&amp;quot; that record details about each message&#39;s journey. Every time a message moves from one node to another, a span is created to capture where it came from, where it’s going, and how long it took. These spans are linked together, showing the entire path of the message through the system. This makes it easier to spot slowdowns, fix problems, and improve how data moves through Node-RED. The module also makes sure this tracking information follows the message as it moves across different nodes and external services.&lt;/p&gt;
&lt;h2 id=&quot;tracing-in-node-red-flows-using-opentelemetry&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#tracing-in-node-red-flows-using-opentelemetry&quot;&gt;Tracing in Node-RED Flows using Opentelemetry&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a manufacturing plant, Node-RED manages different machines and sensors. Suppose there&#39;s a problem with the production line, such as a delay in processing or a GPIO node experiencing issues reading data. With Open Telemetry integrated, you can trace the data flow through the system to see exactly where the issue is happening. This helps you quickly identify whether the problem is with a specific node that is reading the machine data or a delay in data processing, allowing you to fix the issue faster and keep the production line running smoothly.&lt;/p&gt;
&lt;p&gt;For demonstration purposes, we will use a flow that simulates sensor reading and data processing. We will monitor this flow using Open Telemetry to track data across the system, identify bottlenecks, and optimize performance.&lt;/p&gt;
&lt;div id=&quot;nr-flow-184&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow184 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;78e4a1255f9d0ad1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;45e56b4089cada94&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;636ac7b4d798a5c4&#92;&quot;,&#92;&quot;ac87db82c2ab66f5&#92;&quot;,&#92;&quot;c8a1749629359031&#92;&quot;,&#92;&quot;c0d30281031f07db&#92;&quot;],&#92;&quot;x&#92;&quot;:34,&#92;&quot;y&#92;&quot;:139,&#92;&quot;w&#92;&quot;:852,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;636ac7b4d798a5c4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;45e56b4089cada94&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;78e4a1255f9d0ad1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temperature sensor&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;300&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c8a1749629359031&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac87db82c2ab66f5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;45e56b4089cada94&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;78e4a1255f9d0ad1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c8a1749629359031&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;45e56b4089cada94&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;78e4a1255f9d0ad1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Kelvin to Celsius&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload - 273.15&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c0d30281031f07db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c0d30281031f07db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;45e56b4089cada94&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;78e4a1255f9d0ad1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac87db82c2ab66f5&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow184.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-184&#39;) })&lt;/script&gt;
&lt;p&gt;Deploy the flow above, and you might see a delay in the data shown on the debug panel. For this example, we added a Delay node before the Change node that converts temperature data from Kelvin to Celsius. While this delay is visible here, finding such delays in larger flows with many nodes can be difficult and time-consuming. Open Telemetry makes this easier by giving you detailed traces that show where delays or issues are happening&lt;/p&gt;
&lt;h3 id=&quot;prerequisite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#prerequisite&quot;&gt;Prerequisite&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before you start, ensure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opentelemetry&quot;&gt;node-red-contrib-opentelemetry&lt;/a&gt; : Install this Node-RED module via the Node-RED Palette Manager.&lt;/li&gt;
&lt;li&gt;Open Telemetry exporter: Set up an Open Telemetry exporter to send trace data to a backend. For details on available exporters, visit &lt;a href=&quot;https://opentelemetry.io/docs/instrumentation/js/exporters/&quot;&gt;Open Telemetry Exporters&lt;/a&gt;. For this guide, I have set up the &lt;a href=&quot;https://jaegertracing.io/&quot;&gt;Jaeger&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;setting-open-telemetry-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#setting-open-telemetry-in-node-red&quot;&gt;Setting Open Telemetry in Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the configuration of opentelmetry node&quot; alt=&quot;&amp;quot;Screenshot showing the configuration of opentelmetry node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opentelmetry-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the configuration of opentelmetry node&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;code&gt;OTEL&lt;/code&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node and set the URL to your exporter endpoint (e.g., &lt;code&gt;http://localhost:4318/v1/traces&lt;/code&gt; for a locally running Jaeger exporter). Provide a name for the service according to your preference, and set the Prefix, which will be added to the root Node-RED span name before the initial node name (you can keep it as &amp;quot;Message&amp;quot; if preferred).&lt;/li&gt;
&lt;li&gt;In the Ignore field, add the names of nodes you want to exclude from Open Telemetry tracing.&lt;/li&gt;
&lt;li&gt;In the Propagate field, add the names of nodes if you want them to forward trace headers to external systems or other nodes in the flow. This ensures that these nodes participate in the distributed trace, allowing the trace context to be maintained across different components.&lt;/li&gt;
&lt;li&gt;Set the Timeout to define how long (in seconds) the OTEL node should wait before ending and discarding a message that has not been modified.&lt;/li&gt;
&lt;li&gt;Now deploy the flow by clicking on the top-right deploy button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the flow is deployed, Open Telemetry will start collecting and sending trace data to your specified exporter.&lt;/p&gt;
&lt;h3 id=&quot;monitoring-performance-using-the-exporter-web-ui&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#monitoring-performance-using-the-exporter-web-ui&quot;&gt;Monitoring Performance Using the Exporter Web UI&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&#39;s monitor the performance and latency between each node to identify delays. For this section, I am assuming you have Jaeger running as your exporter.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Jaeger web UI in your browser. By default, it will be available at &lt;code&gt;http://localhost:16686/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &amp;quot;Search&amp;quot; by clicking on the &amp;quot;Search&amp;quot; option at the top.&lt;/li&gt;
&lt;li&gt;Select the service name that you configured in the OTEL node from the service field. Once selected, you will see all the traces for each interaction in the flow. You can filter the traces by specific nodes using the operation field.&lt;/li&gt;
&lt;li&gt;To monitor and find issues, select the desired trace and click on the &amp;quot;Find Trace&amp;quot; button. Click on the first trace to examine it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the trace opens, you will see the duration taken by each node to process and pass data. Notice the time taken by the delay node, which is 2 seconds, indicating the problem. By clicking on the green line corresponding to this delay node, you can view more detailed information about the trace.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the total duration taken by the flow&quot; alt=&quot;&amp;quot;Image showing the total duration taken by the flow&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/before.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the tototal duration taken by the flow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since the issue was identified with the delay node, let&#39;s remove that delay node.&lt;/p&gt;
&lt;div id=&quot;nr-flow-185&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow185 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;636ac7b4d798a5c4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;350fb9fbb98012be&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temperature sensor&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;300&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c8a1749629359031&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac87db82c2ab66f5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;350fb9fbb98012be&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:640,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c8a1749629359031&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;350fb9fbb98012be&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Kelvin to Celsius&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload - 273.15&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac87db82c2ab66f5&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow185.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-185&#39;) })&lt;/script&gt;
&lt;p&gt;After updating the flow, redeploy the flow and check the traces again. You should see that the total time has been reduced significantly, with the overall flow now taking around 8 milliseconds instead of the previous 2 seconds. This demonstrates how Open Telemetry helps in identifying and resolving performance issues in your Node-RED flows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the total duration taken by the flow after fixing the issue&quot; alt=&quot;&amp;quot;Image showing the total duration taken by the flow after fixing the issue&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/after.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the total duration taken by the flow after fixing the issue&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Throughout this guide, we’ve interacted with an exporter which is running locally. However, by deploying and setting up your exporter on a server, you can remotely monitor the performance of your Node-RED flows. This setup enables you to oversee your system&#39;s performance from anywhere, making it easier to detect and address issues promptly.&lt;/p&gt;
&lt;h2 id=&quot;enhancing-monitoring-and-optimization-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#enhancing-monitoring-and-optimization-with-flowfuse&quot;&gt;Enhancing Monitoring and Optimization with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While OpenTelemetry excels at tracing and optimizing Node-RED flows, FlowFuse offers a powerful solution for managing and monitoring Node-RED instances. It streamlines the creation, deployment, and management of instances, allowing you to deploy your applications with a single click and minimizing deployment complexity and errors.&lt;/p&gt;
&lt;p&gt;FlowFuse also boosts collaboration and security through features like team management, role-based access control, multi-factor authentication, and snapshot recovery. These capabilities ensure effective management, secure access, and easy recovery from changes, making FlowFuse an essential tool for optimizing and overseeing your Node-RED deployments.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opentelemetry-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating OpenTelemetry with Node-RED enables you to efficiently trace and resolve delays in your flows, ensuring smoother and more efficient operation of your IoT applications. By following the steps outlined in this guide, you can leverage distributed tracing to identify performance bottlenecks and optimize your flows effectively. With OpenTelemetry&#39;s detailed insights and FlowFuse&#39;s robust features, you&#39;ll be well-equipped to maintain peak performance and manage your Node-RED environment seamlessly.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/</id>
        <title>Bridging OPC UA Data to MQTT with Node-RED</title>
        <summary>Connecting OPC UA Data Streams to MQTT Brokers for Enhanced IoT Communication and Monitoring</summary>
        <updated>2024-08-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever found yourself trying to connect old industrial systems with new IoT tools? This is a common scenario when trying to digitally transform while setting up your Unified Name Space. Maybe you have machinery that uses OPC UA, but your data is sent through MQTT. How do you make these systems work together smoothly?&lt;/p&gt;
&lt;p&gt;In this guide, we&#39;ll demonstrate how to use Node-RED to bridge OPC UA data to MQTT. This integration will streamline your data flow and enhance real-time monitoring, helping you modernize your setup and improve communication between systems.&lt;/p&gt;
&lt;h3 id=&quot;why-bridge-opc-ua-to-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#why-bridge-opc-ua-to-mqtt&quot;&gt;Why Bridge OPC UA to MQTT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Diagram showing the data flow when bridging OPC UA to MQTT to enable communication between non-OPC UA compatible systems and devices&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-ua-to-mqtt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Diagram showing the data flow when bridging OPC UA to MQTT to enable communication between non-OPC UA compatible systems and devices.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In modern industrial environments, integrating systems with different communication protocols can be a significant challenge. For example, a CNC machine on the factory floor might use OPC UA, while some cloud solutions, edge devices, and other systems, such as custom ERP solutions and IoT applications, might rely on MQTT protocol. This is where bridging OPC UA to MQTT becomes highly beneficial.&lt;/p&gt;
&lt;p&gt;By converting OPC UA data into MQTT messages, you make the data from the CNC machine accessible to a broader range of systems that use MQTT, which is a more universally supported messaging protocol. This bridging solution simplifies the integration process, allowing diverse systems to communicate effectively without needing direct OPC UA support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node-RED&lt;/strong&gt; is perfect for this job. It can connect both OPC UA and MQTT, making it easy to transform and route data between different systems. Its flexibility and support for many protocols make it great for integrating various industrial hardware and software. For more on how Node-RED can improve industrial operations, check out &lt;a href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/&quot;&gt;Building on FlowFuse: Remote Device Monitoring&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bridging-opc-ua-data-to-mqtt-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#bridging-opc-ua-data-to-mqtt-with-node-red&quot;&gt;Bridging OPC UA Data to MQTT with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, I&#39;ll demonstrate how to bridge OPC UA data to MQTT using Node-RED. We will use simulated OPC UA server data from a CNC machine as an example. The goal is to show how you can efficiently transfer this data to an MQTT broker, making it accessible to various applications and systems.&lt;/p&gt;
&lt;h3 id=&quot;prerequisite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#prerequisite&quot;&gt;Prerequisite&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;OPC UA Server: Make sure you have an OPC UA server configured and running with the necessary data. For this blog, we&#39;ll use the Prosys OPC UA Simulation Server, which simulates data from CNC machines designed for testing OPC UA client applications and learning the technology. You can download it from &lt;a href=&quot;https://prosysopc.com/products/opc-ua-simulation-server/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FlowFuse Account: A FlowFuse account lets you quickly create, deploy, and manage Node-RED instances in the cloud. &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Bridging%20OPC%20UA%20Data%20to%20MQTT%20with%20Node-RED&quot;&gt;sign up now&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;node-red-contrib-opcua&lt;/a&gt;: install the node-red contrib package that will enable integration of opcua in Node-RED.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MQTT Broker: We’ll need an MQTT broker for data communication. FlowFuse offers an integrated MQTT Broker Service within Platform for easy setup. For more details, check out &lt;a href=&quot;https://flowfuse.com/blog/2024/10/announcement-mqtt-broker/&quot;&gt;FlowFuse&#39;s MQTT Broker Announcement&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;retrieving-data-from-the-opc-ua-server&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#retrieving-data-from-the-opc-ua-server&quot;&gt;Retrieving Data from the OPC UA Server&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To begin retrieving data from your OPC UA server using Node-RED, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;inject&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;change&lt;/strong&gt; node onto the canvas and double-click on the node to open its configuration settings. Set the &lt;code&gt;msg.topic&lt;/code&gt; to the node ID and datatype of the property you wish to read.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;(Left) Image of the Change node setting the &#39;msg.topic&#39; to retrieve the cycle time data and (Right) the OPC UA Prosys interface.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-setting-nodeid-datatype.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;(Left) Image of the Change node setting the &#39;msg.topic&#39; to retrieve the cycle time data and (Right) the OPC UA Prosys interface.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node onto the canvas. Double-click on it to open its configuration settings. Click the &amp;quot;+&amp;quot; icon next to the Endpoint field and enter the URL of your running OPC UA server. Configure the security policy and mode according to your server setup. If you use the Prosys OPC UA Simulation Server and have not enabled any security features, you can leave the security policy and mode as &amp;quot;None.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring opc-ua client node with the opc ua server endpoint&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-ua-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring opc-ua node with the opc ua server endpoint&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;In the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node settings, select the action type as &amp;quot;READ.&amp;quot; This instructs Node-RED to read data from the OPC UA server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring OpcUa-Client node to select the read operation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-ua-config2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring OpcUa-Client node to select the read operation&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;If your OPC UA server uses security features, specify the path to your certificate files in the relevant fields. If no security is configured, this step can be skipped.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;debug&lt;/strong&gt; node onto the canvas. The output will help you verify the data retrieved from the OPC UA server.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;inject&lt;/strong&gt; node to the input of the &lt;strong&gt;change&lt;/strong&gt; node and the output of the &lt;strong&gt;change&lt;/strong&gt; node to the input of the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node. Then, connect the output of the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node to the input of the &lt;strong&gt;debug&lt;/strong&gt; node. This setup ensures that when the &lt;strong&gt;inject&lt;/strong&gt; node triggers, it sends data to the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node, and the results are displayed in the Debug node.&lt;/li&gt;
&lt;li&gt;Deploy the flow by clicking the &amp;quot;Deploy&amp;quot; button in the top right corner. To test the setup, press the Inject button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can follow the same steps to retrieve other property values from the OPC UA server. In this example, we are retrieving four simulated data properties: the cycle time, temperature, and spindle speed of the simulated CNC machine. Your setup might differ depending on the properties and data available on your OPC UA server.&lt;/p&gt;
&lt;h3 id=&quot;transforming-and-aggregating-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#transforming-and-aggregating-data&quot;&gt;Transforming and Aggregating Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you have successfully retrieved data from your OPC UA server, the next step is to transform and aggregate this data to make it suitable for publishing to an MQTT broker. This demonstration, we will aggregate the retrieved individual property values into a single object. Depending on your specific needs, you might choose to split the object properties and send them separately or perform various calculations and transformations on the data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node and set &lt;code&gt;msg.topic&lt;/code&gt; to the name of the property you want to set for the retrieved data. In this context, set &lt;code&gt;msg.topic&lt;/code&gt; to &lt;code&gt;&#39;cycle-time&#39;&lt;/code&gt;, which will be the key in the object that we will create.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Setting the msg.topic with the Change node to retrieve data from the OPC UA server.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-setting-nodeid-datatype.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Setting the msg.topic with the change node to retrieve data from the OPC UA server.&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag the &lt;strong&gt;join&lt;/strong&gt; node onto the canvas. Set the mode to manual, with the option to create &lt;code&gt;msg.payload&lt;/code&gt; using the values of &lt;code&gt;msg.topic&lt;/code&gt; as keys. Set the count to 3 and ensure that the interval for all of the &lt;strong&gt;inject&lt;/strong&gt; nodes triggering data retrieval is the same. This ensures that the data is collected and aggregated correctly at the same time.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node (which retrieves the data) to the input of the &lt;strong&gt;change&lt;/strong&gt; node. For example, if I have set the &lt;strong&gt;change&lt;/strong&gt; node for the &#39;cycle-time&#39; data property, connect it to the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node that retrieves this data.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;change&lt;/strong&gt; node to the input of the &lt;strong&gt;join&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Repeat this process for all of your data properties.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;sending-data-to-the-mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#sending-data-to-the-mqtt-broker&quot;&gt;Sending Data to the MQTT Broker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now, in this section, we will show you how to send the collected data to an MQTT broker:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;mqtt out&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and configure it with your MQTT broker details.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Configuring the mqtt out node with broker information&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-out-node-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Configuring the mqtt out node with broker information&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Set the topic for your data in the &lt;strong&gt;mqtt out&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;join&lt;/strong&gt; node to the input of the &lt;strong&gt;mqtt out&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Deploy the flow. After deploying, you will see the status &amp;quot;connected&amp;quot; with a green dot at the bottom of each node, indicating that you have successfully connected to your MQTT broker.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the successful bridging of OPC UA data to MQTT&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-to-mqtt.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the successful bridging of OPC UA data to MQTT&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-145&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow145 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a099aefb08837e70&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;read&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f5fd1ffafdfe790f&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1aa02b27b99dfe9d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;/manufacturing/cnc&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;retain&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;respTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;contentType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;correl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expiry&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;x&#92;&quot;:1390,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d565ae620d90498a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;read&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fc4b83a8a0be3a35&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e0614ada3269627&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;read&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e1c4fe72e4f37b6a&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f5fd1ffafdfe790f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set the topic for the data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;cycle-time&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;913e9de1324a6f21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fc4b83a8a0be3a35&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set the topic for the data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;spindle-speed&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;913e9de1324a6f21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e1c4fe72e4f37b6a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set the topic for the data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;temperature&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;913e9de1324a6f21&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;913e9de1324a6f21&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create object from those three data property &#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;custom&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;useparts&#92;&quot;:false,&#92;&quot;accumulate&#92;&quot;:false,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1aa02b27b99dfe9d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3339483f64116fce&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;/manufacturing/cnc&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;auto-detect&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;nl&#92;&quot;:false,&#92;&quot;rap&#92;&quot;:true,&#92;&quot;rh&#92;&quot;:0,&#92;&quot;inputs&#92;&quot;:0,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d881d251071bd317&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d881d251071bd317&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;55f43460af9601ec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retrieving the data from mqtt&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;628ab54495901021&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Bridging OPC UA data to MQTT&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ce6b8a0e2c8a895d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;ns=3;i=1010,datatype=float&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a099aefb08837e70&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;50fe2b9310d3bb3f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;ns=3;i=1011,datatype=basedatatype&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d565ae620d90498a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9cf691f55748d013&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;ns=3;i=1012,datatype=float&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0e0614ada3269627&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de74dabc616c3094&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;807758ec576fbfd8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:120,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ce6b8a0e2c8a895d&#92;&quot;,&#92;&quot;50fe2b9310d3bb3f&#92;&quot;,&#92;&quot;9cf691f55748d013&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://Roni:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;http://broker.hivemq.com&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;autoConnect&#92;&quot;:true,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;autoUnsubscribe&#92;&quot;:true,&#92;&quot;birthTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;birthRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;birthPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthMsg&#92;&quot;:{},&#92;&quot;closeTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;closeRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;closePayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeMsg&#92;&quot;:{},&#92;&quot;willTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;willRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;willPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willMsg&#92;&quot;:{},&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sessionExpiry&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow145.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-145&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;bridging-mqtt-data-to-opc-ua&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#bridging-mqtt-data-to-opc-ua&quot;&gt;Bridging MQTT Data to OPC UA&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to bridging data from OPC UA to MQTT, you might also need to send data from MQTT back to an OPC UA server. This is often required in scenarios where external systems, such as Manufacturing Execution Systems (MES), need to update or control machinery settings.&lt;/p&gt;
&lt;p&gt;For example, an MES can send commands or configuration changes via MQTT, which then need to be applied to an OPC UA-controlled machine.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;mqtt in&lt;/strong&gt; node onto the Node-RED canvas and configure it with your MQTT broker details and the appropriate topic where the MES publishes commands.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;change&lt;/strong&gt; node onto the canvas, Set the &lt;code&gt;msg.topic&lt;/code&gt; to the node ID and datatype of the property you wish to update.&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node to the canvas and configure it with your OPC UA server. Set the action type to &amp;quot;WRITE&amp;quot; to send the received data.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;mqtt in&lt;/strong&gt; node to the input of the &lt;strong&gt;change&lt;/strong&gt; node, and the output of the &lt;strong&gt;change&lt;/strong&gt; node to the input of the &lt;strong&gt;OpcUa-Client&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Image showing the successful bridging of MQTT data to OPC UA&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-to-opcua.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the successful bridging of OPC UA data to MQTT&lt;/em&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-146&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow146 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a099aefb08837e70&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;628ab54495901021&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Bridging MQTT to OPC UA&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ce6b8a0e2c8a895d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;ns=3;i=1010,datatype=Boolean&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;paylad&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:540,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a099aefb08837e70&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0a89ebd0d9f6f577&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;command/cnc/&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;auto-detect&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;nl&#92;&quot;:false,&#92;&quot;rap&#92;&quot;:true,&#92;&quot;rh&#92;&quot;:0,&#92;&quot;inputs&#92;&quot;:0,&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ce6b8a0e2c8a895d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4cf4e425d075722a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;command/cnc/&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;retain&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;respTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;contentType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;correl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;expiry&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8e339e511c573905&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4cf4e425d075722a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9c33cff54b0aca15&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Sending Command&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9dd56eda04f5c5b5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://Roni:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;abd4e6202945fee3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;http://broker.hivemq.com&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;autoConnect&#92;&quot;:true,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;autoUnsubscribe&#92;&quot;:true,&#92;&quot;birthTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;birthRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;birthPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthMsg&#92;&quot;:{},&#92;&quot;closeTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;closeRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;closePayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeMsg&#92;&quot;:{},&#92;&quot;willTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;willRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;willPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willMsg&#92;&quot;:{},&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sessionExpiry&#92;&quot;:&#92;&quot;&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow146.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-146&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/opc-ua-to-mqtt-with-node-red/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/mqtt/&quot;&gt;Using MQTT with Node-RED&lt;/a&gt;
Learn how to integrate MQTT with Node-RED to enhance your IoT solutions with real-time data messaging.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/&quot;&gt;How to Build an OPC UA Client Dashboard in Node-RED&lt;/a&gt;
Follow a step-by-step guide to create a comprehensive OPC UA client dashboard in Node-RED for effective monitoring and control.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/opc-ua/&quot;&gt;Building a Secure OPC UA Server in Node-RED&lt;/a&gt;
Explore best practices for configuring a secure OPC UA server in Node-RED to ensure safe and reliable data exchange.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/&quot;&gt;How to Deploy a Basic OPC UA Server in Node-RED&lt;/a&gt;
Learn how to quickly deploy a basic OPC UA server in Node-RED for testing and development purposes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/&quot;&gt;Node-RED as a No-Code EtherNet/IP to S7 Protocol Converter&lt;/a&gt;
Discover how to use Node-RED to seamlessly convert EtherNet/IP to S7 protocols with Node-RED.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/</id>
        <title>Customise theming in your FlowFuse Dashboard</title>
        <summary>Customising Headers, Themes, and Layouts in FlowFuse Dashboard</summary>
        <updated>2024-08-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A recent release of FlowFuse Dashboard (Dashboard 2.0) has taken customization to the next level.&lt;/p&gt;
&lt;p&gt;Previously, users enjoyed the flexibility of tweaking navigation sidebars, themes, and group and page padding. With the new update, you can fully personalize the header too, adding unique elements to enhance your dashboard experience and customize your application to your own branding.&lt;/p&gt;
&lt;p&gt;In this article, we&#39;ll delve into these exciting new features, including theme adjustments, custom styling, and layout modifications, that empower you to tailor your Node-RED Dashboard like never before.&lt;/p&gt;
&lt;h2 id=&quot;adding-elements-in-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#adding-elements-in-the-header&quot;&gt;Adding Elements in the Header&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To add elements to the header, we can use &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#teleports&quot;&gt;Teleports&lt;/a&gt; within the &lt;code&gt;ui-template&lt;/code&gt; node. This allows elements to be seamlessly rendered in specific areas of the dashboard. This method simplifies the process compared to manually positioning items with CSS, which can be complex, time-consuming, and potentially disruptive to other dashboard elements.&lt;/p&gt;
&lt;h3 id=&quot;left-side-of-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#left-side-of-the-header&quot;&gt;Left Side of the Header&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To render content on the left side of the header, we can teleport content into the &lt;code&gt;#app-bar-title&lt;/code&gt; element, where our page name is displayed.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image of Dashboard showing the #app-bar-title container&quot; alt=&quot;&amp;quot;Screenshot of Dashboard showing the #app-bar-title container&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/left-side-area.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image of Dashboard showing the #app-bar-title container&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;hiding-the-page-name-in-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#hiding-the-page-name-in-the-header&quot;&gt;Hiding the Page Name in the Header&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Before proceeding, you should hide the page name on the left side of the header by default. This will ensure that when you add elements to the header, they do not clash with the page name.&lt;/p&gt;
&lt;p&gt;To hide the page name:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the FlowFuse Dashboard sidebar&lt;/li&gt;
&lt;li&gt;Click on to the &amp;quot;Edit settings&amp;quot; option located at the top of the FlowFuse Dashboard sidebar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-setting-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Untick the option &amp;quot;Show page name in the header bar&amp;quot;.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Show page name in the header bar&#39; option in the dashboard settings&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Show page name in the header bar&#39; option in the dashboard settings&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/settings.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &#39;Show page name in the header bar&#39; option in the dashboard settings&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;example%3A-adding-buttons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#example%3A-adding-buttons&quot;&gt;Example: Adding Buttons&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;code&gt;ui-template&lt;/code&gt; node onto the Node-RED Editor canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and select the scope to either &lt;code&gt;ui-scope&lt;/code&gt; or &lt;code&gt;page-scope&lt;/code&gt;. Selecting &lt;code&gt;ui-scope&lt;/code&gt; will render this content on &lt;em&gt;all&lt;/em&gt; pages. &lt;code&gt;page-scope&lt;/code&gt; will just render to a specified page.&lt;/li&gt;
&lt;li&gt;Choose the page on which you want to render the buttons if you selected &lt;code&gt;page-scope&lt;/code&gt;, or choose correct ui if &lt;code&gt;ui-scope&lt;/code&gt; is selected.&lt;/li&gt;
&lt;li&gt;Paste the following Vue snippet into the template widget. In this snippet, note how we specify the &amp;quot;to&amp;quot; attribute targeting the &lt;code&gt;#app-bar-title&lt;/code&gt; ID in the teleport tag:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-80&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-80&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Teleport the button to the #app-bar-actions area when mounted --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Teleport&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mounted&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#app-bar-title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Button 1&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Button 2&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Button 3&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-btn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Teleport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Set mounted to true when the component is mounted&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mounted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-80&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Next, you can customize further by adding more buttons or different elements inside the &lt;code&gt;&amp;lt;Teleport&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of Dashboard showing the added buttons in the header&quot; alt=&quot;&amp;quot;Screenshot of Dashboard showing the added buttons in the header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/button-added-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Dashboard showing the added buttons in the header&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;example%3A-adding-logo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#example%3A-adding-logo&quot;&gt;Example: Adding Logo&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you want to add your brand&#39;s logo, you can replace the element inside &lt;teleport&gt; with an &lt;img /&gt; tag. You can do this in the same ui-template widget or in a different ui-template widget:&lt;/teleport&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;code&gt;ui-template&lt;/code&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Select the correct scope for that widget to render.&lt;/li&gt;
&lt;li&gt;Select the correct page or UI in which you want to render the element.&lt;/li&gt;
&lt;li&gt;Paste the same Vue snippet given in the above section into the &lt;code&gt;ui-template&lt;/code&gt; widget and replace the code inside &lt;teleport&gt; with the following element:&lt;/teleport&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-119&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-119&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;32px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://app.flowfuse.com/ff-logo--wordmark-caps--dark.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;img&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-119&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can replace the URL with your logo&#39;s URL or set it using the &lt;code&gt;msg.payload&lt;/code&gt; as shown in examples given &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#page-name-app-bar-title&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Dashboard displaying the added logo in the header&quot; alt=&quot;&amp;quot;Screenshot of the Dashboard displaying the added logo in the header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/logo-added-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Dashboard displaying the added logo in the header&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;right-side-of-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#right-side-of-the-header&quot;&gt;Right Side of the Header&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To render elements on the right side of the header, you can use the empty div element having the &lt;code&gt;#app-bar-actions&lt;/code&gt; ID, in which we can add elements.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of Dashboard showing the #app-bar-actions container&quot; alt=&quot;&amp;quot;Screenshot of Dashboard showing the #app-bar-actions container&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/right-side-area.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Dashboard showing the #app-bar-actions container&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;example%3A-adding-logged-in-user-profile&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#example%3A-adding-logged-in-user-profile&quot;&gt;Example: Adding logged in user profile&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of Dashboard displaying the logged in user profile at the right side of header&quot; alt=&quot;&amp;quot;Screenshot of Dashboard displaying the logged in user profile at the right side of header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/user-profile.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of Dashboard displaying the logged in user profile at the right side of header&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this section, we will add the user profile of the currently logged-in user to the right side of the header. Make sure you have installed &amp;quot;@flowfuse/node-red-dashboard-2-user-addon&amp;quot; via the palette manager and enabled &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/#flowfuse-user-authentication&quot;&gt;FlowFuse User Authentication&lt;/a&gt;. Each message emitted by the FlowFuse Dashboard widget will include the logged-in user information under &lt;code&gt;msg._client.user&lt;/code&gt;. Additionally the &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/guides/state-management.html#setup-store&quot;&gt;setup object&lt;/a&gt; will also contain this information under &lt;code&gt;setup.socketio.auth.user&lt;/code&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the ui-template widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Select the correct scope for that widget to render.&lt;/li&gt;
&lt;li&gt;Select the correct page or UI in which you want to render the element.&lt;/li&gt;
&lt;li&gt;Paste the same Vue snippet given below into the &lt;code&gt;ui-template&lt;/code&gt; widget:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-166&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-166&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Teleporting user info to #app-bar-actions, which is the ID of the action bars&#39; right corners area --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Teleport&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;loaded&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#app-bar-actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-info&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Displaying user image --&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;setup.socketio.auth.user.image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Greeting the user --&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hi, &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Teleport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Flag to indicate if the component is loaded&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// This function is called when the component is inserted into the DOM.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Setting loaded to true here ensures the component is ready to access #app-bar-actions,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// as it&#39;s now part of the same DOM structure.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Accessing it before mounted() would cause an error because the component wouldn&#39;t be initialized in the DOM yet.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loaded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Setting loaded to true to indicate that the component has been mounted successfully&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Styling for user info display */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.user-info&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Styling for user avatar image*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.user-info img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-166&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;For detailed guide on this section, refer to the guide on &lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/&quot;&gt;Displaying logged in user on FlowFuse Dashboard&lt;/a&gt;. Furthermore, if you want to add logos or buttons on the right side similar to the left side of the header, you just need to replace the to attribute with the &lt;code&gt;#app-bar-actions&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;centering-header-items&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#centering-header-items&quot;&gt;Centering Header Items&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes you may want to center or position items added to either the &lt;code&gt;#app-bar-title&lt;/code&gt; or the &lt;code&gt;#app-bar-actions&lt;/code&gt;. By default, these elements do not have a specified width, and when you add items into them, they grow to fit their content. To center the elements, you first need to ensure that they are sized appropriately.&lt;/p&gt;
&lt;h4 id=&quot;centering-items-in-the-left-side-of-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#centering-items-in-the-left-side-of-the-header&quot;&gt;Centering Items in the Left Side of the Header&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To center items added to the &lt;code&gt;#app-bar-title&lt;/code&gt;, apply the following CSS in the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag of the &lt;code&gt;ui-template&lt;/code&gt; widget:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-182&quot;&gt;
  &lt;pre class=&quot;language-css&quot;&gt;&lt;code id=&quot;code-182&quot; class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#app-bar-title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;flex-grow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-182&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;centering-items-in-the-right-side-of-the-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#centering-items-in-the-right-side-of-the-header&quot;&gt;Centering Items in the Right Side of the Header&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To center items in the &lt;code&gt;#app-bar-actions&lt;/code&gt; area, add the following CSS to the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag of the &lt;code&gt;ui-template&lt;/code&gt; widget:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-189&quot;&gt;
  &lt;pre class=&quot;language-css&quot;&gt;&lt;code id=&quot;code-189&quot; class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#v-toolbar__append&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;flex-grow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-189&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;styling-header&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#styling-header&quot;&gt;Styling Header&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the significant customization features we&#39;ve added recently is the ability to style the header in different ways.&lt;/p&gt;
&lt;p&gt;To style the header:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the FlowFuse Dashboard sidebar&lt;/li&gt;
&lt;li&gt;Click on to the &amp;quot;Edit settings&amp;quot; option located at the top of the FlowFuse Dashboard sidebar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-setting-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &#39;edit setting&#39; option in the dashboard sidebar&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Select the desired option from the &amp;quot;Header Options&amp;quot; dropdown.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the header style options in the dashboard settings&quot; alt=&quot;&amp;quot;Screenshot showing the header style options in the dashboard settings&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/header-style-options.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the header style options in the dashboard settings&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The following options are available for header styling:&lt;/p&gt;
&lt;h3 id=&quot;default&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#default&quot;&gt;Default&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This option as it name suggest it is the default option set for header. In which the header will get hidden if we scrolled down.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the dashboard with default header&quot; alt=&quot;&amp;quot;Image showing the dashboard with default header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/default-header.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the dashboard with default header&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;hidden&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#hidden&quot;&gt;Hidden&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Selecting this option completely hides the header, allowing you to use that space for other purposes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the dashboard with hidden header&quot; alt=&quot;&amp;quot;Image showing the dashboard with hidden header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/hidden-header.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the dashboard with hidden header&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;fixed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#fixed&quot;&gt;Fixed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Selecting this option keeps the header fixed at the top. This means that when you scroll the page down, the header will remain visible.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the dashboard with fixed header&quot; alt=&quot;&amp;quot;Image showing the dashboard with fixed header&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/fixed-header.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image showing the dashboard with fixed header&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;changing-dashboard-theme&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#changing-dashboard-theme&quot;&gt;Changing Dashboard Theme&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section of the guide, you will learn how to change the Dashboard theme, where you can adjust the colors of the header, navigation sidebar, group and page backgrounds, the border color of groups, and the padding, sizing, and gaps between pages, groups, and widgets.&lt;/p&gt;
&lt;p&gt;To edit the existing theme:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the FlowFuse Dashboard sidebar.&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Theme&amp;quot; tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the dashboard theme tab in the sidebar&quot; alt=&quot;&amp;quot;Screenshot showing the dashboard theme tab in the sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-theme-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the dashboard theme tab in the sidebar&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on the edit button next to the theme.&lt;/li&gt;
&lt;li&gt;You can adjust the header color and the primary color (which applies to the navigation sidebar and elements like buttons and dropdowns) under the &amp;quot;Primary&amp;quot; section. In the &amp;quot;Pages&amp;quot; section, set the background color for pages, and in the &amp;quot;Groups&amp;quot; section, adjust the background color and border color of groups.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the theme properties dialog&quot; alt=&quot;&amp;quot;Screenshot showing the theme properties dialog&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-theme-settings.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the theme properties dialog&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Under &amp;quot;Sizing,&amp;quot; adjust the page padding (the space between dashboard groups), the page border, group gap, group border radius (the thickness of the group border), and widget gap.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information on  theme, how to add new themes, and set themes for pages, refer to the &lt;a href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#understanding-dashboard-2.0-theme&quot;&gt;Comprehensive guide: FlowFuse Dashboard layout, sidebar, and styling&lt;/a&gt;. Additionally, this guide covers FlowFuse Dashboard layouts, themes, and custom styling in detail.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/customise-theming-in-your-dashboards/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this article, we explored FlowFuse Dashboard&#39;s new customization features. We focused on adding elements like buttons and logos to the header, and discussed styling options such as default, hidden, and fixed for headers. We also covered how to adjust dashboard themes to personalize colors and layout. These insights empower users to create more personalized and functional Node-RED dashboards.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/</id>
        <title>FlowFuse Dashboard vs UI-Builder: A Comprehensive Comparison</title>
        <summary>Understanding the Differences Between FlowFuse Dashboard and UI-Builder</summary>
        <updated>2024-08-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;When choosing a dashboard solution for Node-RED, two popular options are FlowFuse Dashboard (also known as Dashboard 2.0) and UI-Builder. This article compares these tools across several key areas, including installation, ease of use, development activity, and customizability, to help you decide which one best suits your needs.&lt;/p&gt;
&lt;h2 id=&quot;how-easy-is-it-to-install%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-easy-is-it-to-install%3F&quot;&gt;How Easy is it to Install?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When searching for &lt;code&gt;flowfuse/node-red-dashboard&lt;/code&gt; on Google, the first result we get to the documentation, which is useful. However, in the Node-RED Palette Manager, finding the correct package can be confusing because there are many community third-party nodes and plugins that work with FlowFuse Dashboard. This can make it bit confusing for new users to locate the right package.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Finding UI-Builder is straightforward, as its package name &lt;code&gt;node-red-contrib-uibuilder&lt;/code&gt; is distinct and easily identifiable both on Google and in the Node-RED Palette Manager. This clear naming helps users quickly locate the correct package.&lt;/p&gt;
&lt;h2 id=&quot;how-easy-is-it-to-get-started%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-easy-is-it-to-get-started%3F&quot;&gt;How Easy is it to Get Started?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-1&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Getting started with FlowFuse Dashboard is relatively easy due to its low-code approach. It features a sidebar for managing UI widgets, themes, configurations, and settings, with intuitive navigation to the dashboard page. This makes it accessible for users with varying levels of technical expertise.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-1&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder can be more challenging to start with, as it does not follow a low-code approach and lacks a separate sidebar for managing UI elements. Navigating dashboards built with UI-Builder can be less straightforward, and it requires users to have a deeper understanding of coding and UI design principles.&lt;/p&gt;
&lt;h2 id=&quot;migrating-from-node-red-dashboard-(dashboard-1.0)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#migrating-from-node-red-dashboard-(dashboard-1.0)&quot;&gt;Migrating from Node-RED Dashboard (Dashboard 1.0)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-dashboard&quot;&gt;Node-RED Dashboard&lt;/a&gt; is a module that provides a set of nodes in Node-RED to quickly create user interfaces or live data dashboards. It was developed by one of the creators of Node-RED and is the most used and downloaded package in the Node-RED ecosystem. However, it is now deprecated. For more information, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/&quot;&gt;Node-RED Dashboard Formally Deprecated&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-dashboard-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-2&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard is developed to replace the the deprecated standard Node-RED Dashboard. It retains the core concepts and UI elements but introduces more advanced options and configurations.&lt;/p&gt;
&lt;p&gt;To facilitate the transition, FlowFuse, the creator of FlowFuse Dashboard, provides a &lt;a href=&quot;https://flowfuse.com/platform/dashboard/#migration-service&quot;&gt;migration service&lt;/a&gt; that simplifies migration of flows or projects from the Node-RED Dashboard to FlowFuse Dashboard. This service helps ensure a smoother migration process with minimal disruption.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-2&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Migrating from Node-RED Dashboard 1 to UI-Builder is significantly more complex. UI-Builder does not follow the same concepts or provide the same UI elements as the Node-RED Dashboard.&lt;/p&gt;
&lt;p&gt;Users will need to recreate their dashboards from scratch, as UI-Builder relies on custom coding and frontend frameworks rather than the predefined, low-code widgets of Node-RED Dashboard. This process can be overwhelming and requires a solid understanding of HTML, CSS and the frontend frameworks if you wanted use.&lt;/p&gt;
&lt;h2 id=&quot;how-active-is-the-project&#39;s-development%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-active-is-the-project&#39;s-development%3F&quot;&gt;How Active is the Project&#39;s Development?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-3&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/graphs/contributors&quot;&gt;FlowFuse Dashboard&lt;/a&gt;, which replaced Node-RED Dashboard 1.0 in 2023, has shown consistent and high development activity. The project benefits from a dedicated team that regularly updates and improves it, ensuring it remains current with user needs and technological advancements.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of the FlowFuse Dashboard GitHub commit chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-2-commits.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot of the FlowFuse Dashboard GitHub commit chart.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-3&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/TotallyInformation/node-red-contrib-uibuilder/graphs/contributors&quot;&gt;UI-Builder&lt;/a&gt; has been an active project for a long time and remains active. However, there has been a noticeable decline in development activity starting in early 2024. While the project continues to be maintained, it does not have a dedicated, full-time team.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of the UI-Builder GitHub commit chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-builder-commits.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;br /&gt;
&lt;em&gt;Screenshot of the UI-Builder GitHub commit chart.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;pre-built-ui-elements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#pre-built-ui-elements&quot;&gt;Pre-Built UI Elements&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-4&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard offers an extensive set of UI elements, including forms, dropdowns, tables, charts, and gauges that are super easy to use. These widgets are built with complex Vue.js components, but users are completely shielded from this complexity, allowing them to focus on ease of use. Additionally, if you want to create your own custom widget, you can do so with the ui-template node that accepts complete Vue components. By default, FlowFuse Dashboard supports the Vuetify library, which provides an extensive set of UI components.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-4&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder also offers a number of widgets, but these are not as user-friendly as those in FlowFuse Dashboard. Users must send a JSON config object, which can be complex for new users who lack knowledge of HTML/CSS. Additionally, handling widget data requires using UI-Builder&#39;s methods, which can further increase complexity. However, UI-Builder&#39;s strength lies in its flexibility, allowing any HTML element to be used as a component, and it also supports the W3C standard web components. Despite this, users need to perform a lot of additional tasks to get everything set up and will have the hassle of writing things.&lt;/p&gt;
&lt;h2 id=&quot;changing-the-ui-at-runtime&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#changing-the-ui-at-runtime&quot;&gt;Changing the UI at Runtime&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-5&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-5&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard supports dynamic control of the UI via the msg object. Each UI widget supports the &lt;code&gt;msg.ui_update&lt;/code&gt; property, which allows you to control and update UI components dynamically. For example, you can update form fields based on user input, dynamically insert or update options in a dropdown, or change the appearance of the UI by sending CSS classes or selecting options in dropdowns or radio buttons through msg.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-5&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-5&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder also supports dynamic UI updates and control. Similar to FlowFuse Dashboard, you can use messages to control the state and content of UI elements.&lt;/p&gt;
&lt;h2 id=&quot;data-visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#data-visualization&quot;&gt;Data Visualization&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-6&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-6&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Monitoring devices is one of the core use cases for Node-RED, and FlowFuse Dashboard makes it easy to monitor device metrics with its built-in &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-chart.html&quot;&gt;chart&lt;/a&gt; and &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-gauge.html&quot;&gt;gauge widgets&lt;/a&gt;. The chart widgets support various types, including line, bar, scatter, pie, and donut charts, while the gauge widgets offer options like tile, 3/4 gauge, and half gauge. This range of built-in options simplifies the creation of visualizations for monitoring device metrics. Additionally, you can use Vuetify or other third-party libraries in the ui-template node if you need different types of charts.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-6&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-6&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder does not provide built-in charting options. However, you can add charts using third-party JavaScript libraries. This approach requires additional effort to integrate and configure the libraries, as well as writing the relevant JavaScript to render the charts. While this increases the complexity of creating visualizations, it offers more control and customization.&lt;/p&gt;
&lt;h2 id=&quot;building-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#building-layout&quot;&gt;Building Layout&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-7&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard offers a collection of pre-defined layouts to make it easy for users to get started quickly. These are available as a configuration for each &amp;quot;Page&amp;quot; of your application.&lt;/p&gt;
&lt;p&gt;These predefined layouts provide a solid foundation for most applications. If you need a different layout, FlowFuse Dashboard is limited in it&#39;s customization in terms of positioning of elements.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-7&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder does not come with predefined layouts, which can make it more complex for users to get started. it does however, provides the flexibility to completely define your own layout using CSS. This approach allows for complete customization, but it requires users to have a good understanding of HTML and CSS. The lack of predefined layouts means users have to create their own from scratch, which can be time-consuming.&lt;/p&gt;
&lt;h2 id=&quot;responsiveness-on-mobile&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#responsiveness-on-mobile&quot;&gt;Responsiveness on Mobile&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-8&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-8&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard is designed with &lt;a href=&quot;https://dashboard.flowfuse.com/layouts/&quot;&gt;responsiveness&lt;/a&gt; in mind. It ensures that dashboards automatically adapt to different screen sizes and devices, providing a consistent user experience across desktops, tablets, and mobile devices. The dashboard elements are automatically adjusted to fit various resolutions, making it user-friendly for a wide audience.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-8&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-8&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder&#39;s support for different devices depends on the user&#39;s implementation. While it offers the potential for responsive designs, achieving this requires a good understanding of responsive design principles and CSS.&lt;/p&gt;
&lt;h2 id=&quot;how-much-customization-is-available%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-much-customization-is-available%3F&quot;&gt;How Much Customization is Available?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-9&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-9&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard, built on Vue.js, offers a range of customization options through its widget configurations and settings.&lt;/p&gt;
&lt;p&gt;While it provides predefined UI elements, users can override CSS and theming using the &lt;a href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/&quot;&gt;ui_template&lt;/a&gt; widget to enhance the dashboard&#39;s appearance.&lt;/p&gt;
&lt;p&gt;This same widget also provides functionality to develop custom components or widgets for your Dashboard. These must be built with a VueJS core, but do support the integration of third-party JavaScript libraries.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-9&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-9&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder provides extensive customization capabilities, enabling users to build and style UI elements from scratch. This flexibility is advantageous for those with a strong background in frontend development, as it supports any frontend framework or custom design approach. However, achieving the desired results requires significant time and expertise, as users need to handle the coding and styling for each UI element they create.&lt;/p&gt;
&lt;h2 id=&quot;can-it-be-installed-on-mobile%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#can-it-be-installed-on-mobile%3F&quot;&gt;Can it be Installed on Mobile?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-10&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-10&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard is built and deployed as a Progressive Web App. This means whilst it&#39;s built as a web application, it can be &lt;a href=&quot;https://dashboard.flowfuse.com/user/pwa.html#installing-dashboards-on-mobile&quot;&gt;installed on your mobile device&lt;/a&gt; and run as a standalone application, behaving as if it was a native app.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-10&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-10&quot;&gt;Ui-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dashboards built with UI-Builder, on the other hand, cannot be installed as an app. It is designed as a web-based tool for building custom UIs and does not support installation as a standalone application.&lt;/p&gt;
&lt;h2 id=&quot;how-about-performance-and-speed%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-about-performance-and-speed%3F&quot;&gt;How About Performance and Speed?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-11&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-11&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard provides reliable performance with efficient real-time updates. Initial page load times might be slower, particularly on mobile, but the overall performance is consistent and effective for dynamic dashboards.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-11&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-11&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder provides faster initial load times and smooth performance across customizations, ensuring high-speed interactions.&lt;/p&gt;
&lt;h2 id=&quot;how-is-the-overall-user-experience%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-is-the-overall-user-experience%3F&quot;&gt;How is the Overall User Experience?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-12&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-12&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard offers a user-friendly experience with its low-code approach, intuitive UI, and extensive documentation. Users can quickly create and customize dashboards without needing advanced coding skills, making it accessible to a wide range of users, from beginners to experienced developers. This allows users to focus on solving business problems and IoT tasks rather than getting bogged down by complex coding requirements.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-12&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-12&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder provides a more flexible but complex user experience. While it allows for greater customization and the use of any frontend framework, it requires a solid understanding of coding and design principles. This can be daunting for users without a background in web development, but it offers powerful capabilities for those who are comfortable with custom coding.&lt;/p&gt;
&lt;h2 id=&quot;how-active-is-the-user-community%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-active-is-the-user-community%3F&quot;&gt;How Active is the User Community?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-13&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-13&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard boasts a large and active user community. Users frequently participate in forums, contribute to discussions, and share custom solutions. The number of weekly downloads is growing rapidly, reflecting its high activity and popularity.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&amp;quot;Screenshot of the FlowFuse Dashboard package&#39;s weekly download chart from npm&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-2-download.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the FlowFuse Dashboard package&#39;s weekly download chart from npm&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-13&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-13&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder has a smaller but still active user community. While not as large as FlowFuse Dashboard&#39;s, it includes dedicated users who also engage in forums, contribute to discussions, and share their use cases and solutions.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&amp;quot;Screenshot of the Ui-Builder package&#39;s weekly download chart from npm&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-builder-downloads.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Ui-Builder package&#39;s weekly download chart from npm&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-good-is-the-support-and-documentation%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#how-good-is-the-support-and-documentation%3F&quot;&gt;How Good is the Support and Documentation?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-14&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-14&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Support for FlowFuse Dashboard is robust, with assistance from both the FlowFuse team and the active Node-RED community. The documentation is comprehensive, easy to understand, and regularly updated. The team is also working on an interactive dashboard solution for previewing examples.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-14&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-14&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder also has good support, with active contributions from the author and the Node-RED community. The documentation is detailed but can be complex due to extensive use of technical language.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-future-development-plans%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#what-are-the-future-development-plans%3F&quot;&gt;What are the future development plans?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-dashboard-15&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#flowfuse-dashboard-15&quot;&gt;FlowFuse Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse Dashboard is actively working on enhancing its feature set. With extensive functionality already in place, the project also has ambitious plans to introduce more advanced features to better serve its users. You can track these developments on the &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;FlowFuse Dashboard GitHub project board&lt;/a&gt;, where ongoing and upcoming features are documented.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&amp;quot;Screenshot of the FlowFuse Dashboard GitHub project board&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-2-project-plan.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the FlowFuse Dashboard GitHub project board&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Additionally, updates about new features and enhancements are also provided through social media, blogs, and the Node-RED forums, ensuring that users stay informed about the latest developments.&lt;/p&gt;
&lt;h3 id=&quot;ui-builder-15&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#ui-builder-15&quot;&gt;UI-Builder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;UI-Builder does not have a publicly accessible project roadmap or a dedicated planning board for future updates. While development continues, details about forthcoming features and enhancements are regularly updated on the Node-RED Discourse forums by its author.&lt;/p&gt;
&lt;h2 id=&quot;summary-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#summary-table&quot;&gt;Summary Table&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;FlowFuse Dashboard&lt;/th&gt;
&lt;th&gt;UI-Builder&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Installation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Moderately easy&lt;/strong&gt;: Search for &lt;code&gt;flowfuse/node-red-dashboard&lt;/code&gt; can be confusing due to multiple nodes; useful documentation available&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Easy&lt;/strong&gt;: Clear package name &lt;code&gt;node-red-ui-builder&lt;/code&gt; makes it straightforward to find&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Getting Started&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Easy&lt;/strong&gt;: Low-code interface with a sidebar for managing UI elements; intuitive for users of varying technical skills&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Challenging&lt;/strong&gt;: Requires understanding of coding and UI design; lacks a low-code approach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Migration from Node-RED Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Smooth&lt;/strong&gt;: Migration service provided to transition from Node-RED Dashboard 1 to FlowFuse Dashboard&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Complex&lt;/strong&gt;: Requires rebuilding dashboards from scratch; significant effort needed for migration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Development Activity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;: Regular updates and improvements; actively maintained by a dedicated team&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Moderate&lt;/strong&gt;: Active but shows a decline in updates; less frequent enhancements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI Elements Collection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Extensive&lt;/strong&gt;: Includes a wide range of widgets like forms, charts, and gauges; built on Vue.js with Vuetify support&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flexible but complex&lt;/strong&gt;: Allows any HTML element; requires custom coding and handling of UI elements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visualization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Easy&lt;/strong&gt;: Built-in charting options for various types; additional options with third-party libraries&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Complex&lt;/strong&gt;: No built-in charts; requires integration of third-party libraries for visualization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic UI Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Supported&lt;/strong&gt;: Can dynamically control and update UI components using &lt;code&gt;msg.ui_update&lt;/code&gt; property&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Supported&lt;/strong&gt;: Dynamic updates possible, but can be more complex to implement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Layout Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Predefined&lt;/strong&gt;: Offers three main layouts with some options for custom styling&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Customizable&lt;/strong&gt;: No predefined layouts; users must create their own using CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Device and Screen Size Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Excellent&lt;/strong&gt;: Responsive design adapts well to various devices and screen sizes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Variable&lt;/strong&gt;: Responsiveness depends on user&#39;s implementation and knowledge of CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Good&lt;/strong&gt;: Offers customization through widget settings and custom CSS and ui-template; supports Vue components and third-party libraries&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;: Full control over UI design and layout with custom coding; requires expertise in frontend development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Installation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Available&lt;/strong&gt;: Can be installed as a Progressive Web App (PWA) for use as a standalone application&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Not available&lt;/strong&gt;: Designed as a web-based tool; cannot be installed as an app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance and Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reliable&lt;/strong&gt;: Good performance with consistent updates; may have slower initial load times on mobile&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Good&lt;/strong&gt;: Generally good performance on both desktop and mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Support and Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Robust&lt;/strong&gt;: Comprehensive, regularly updated documentation and active community support&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Good&lt;/strong&gt;: Detailed but may be complex; documentation includes technical jargon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall User Experience&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;User-friendly&lt;/strong&gt;: Accessible and easy to use with low-code approach; suitable for a wide range of users&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flexible but complex&lt;/strong&gt;: Offers greater customization but requires coding expertise; can be daunting for non-developers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Community Activity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Large and active&lt;/strong&gt;: High engagement in forums and discussions; growing number of downloads&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Smaller but dedicated&lt;/strong&gt;: Active users, but less engagement compared to FlowFuse Dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Future Development Plans&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Active&lt;/strong&gt;: Continuous enhancements and new features planned; updates tracked on GitHub project board&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Less transparent&lt;/strong&gt;: No detailed roadmap; future features are less clearly communicated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/comparing-dashboard-2-with-uibuilder/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Dashboard is well-suited for users seeking a user-friendly, low-code solution with a wide range of pre-built elements and strong community support. Its ease of use and active development make it ideal for quick deployment and minimal technical overhead.&lt;/p&gt;
&lt;p&gt;UI-Builder, however, offers nice performance and customization, benefiting users with coding expertise who need highly tailored UIs. Despite its flexibility and faster load times, it requires more complex setup and migration.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/</id>
        <title>FlowFuse 2.7: Improved management at scale &amp; AI JSON Editor</title>
        <summary>We&#39;ve extended the AI-infused Node-RED experience to the JSON Editor, plus improvements to managing and searching your resources on FlowFuse.</summary>
        <updated>2024-08-01T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.7 has had a big focus on user experience improvements, particularly centered around teams running at large scales, with over a thousand devices and instances. With this in mind, we&#39;ve introduced a new search feature that allows you to search across all of your FlowFuse instances, devices and applications from a single place, made it easier to manage your devices with bulk actions, introduced a new notifications inbox to give you a clearer picture on activity across your team, and just for good measure, we&#39;ve also extended the AI-infused Node-RED experience to the JSON Editor.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-expert-in-the-json-editor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#flowfuse-expert-in-the-json-editor&quot;&gt;FlowFuse Expert in the JSON Editor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last release we saw the introduction of the FlowFuse Expert, and in this release we&#39;re rolling this out further to include Node-RED&#39;s JSON Editor.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;(Left) Screenshot of the AI prompt for a list of 4-legged creatures and (Right) the resulting JSON generated by the FlowFuse Expert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ask-assistant-json.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;(Left) Screenshot of the AI prompt for a list of 4-legged creatures and (Right) the resulting JSON generated by the FlowFuse Expert&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;(Left) Screenshot of the AI prompt input for a list of simulated devices and (Right) the resulting JSON generated by the FlowFuse Expert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ask-assistant-json-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;(Left) Screenshot of the AI prompt input for a list of simulated devices and (Right) the resulting JSON generated by the FlowFuse Expert&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This new feature empowers you to create custom data sets within seconds, meaning you can sketch out Dashboards or test Node-RED flows before connecting to real, production environments.&lt;/p&gt;
&lt;h2 id=&quot;managing-resources-at-scale&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#managing-resources-at-scale&quot;&gt;Managing Resources at Scale&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned in the introduction, a big focus on this release, and moving forward into the next couple too, is around improving the user experience when managing large numbers of devices and instances.&lt;/p&gt;
&lt;h3 id=&quot;centralized-search&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#centralized-search&quot;&gt;Centralized Search&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have customers with over a thousand devices and instances running in FlowFuse. It can be very difficult to find the resource you&#39;re looking for. That&#39;s why we&#39;ve introduced a new search feature that allows you to search across all of your FlowFuse instances, devices and applications from a single place.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Application Search feature in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/applications-search.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new Application Search feature in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The search filters as you type, making it easy to find the resource you&#39;re looking for. It will keep reference to any applications and or child instances/devices where appropriate too.&lt;/p&gt;
&lt;h3 id=&quot;notifications-inbox&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#notifications-inbox&quot;&gt;Notifications Inbox&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Notifications Inbox in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/notifications-inbox.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new Notifications Inbox in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a first step in introducing richer notifications across FlowFuse. We&#39;ve introduced a new notifications inbox that will show you all the activity across your team. Currently, this just shows new team invites, but will soon show instance/device activity that needs your attention and more.&lt;/p&gt;
&lt;h3 id=&quot;bulk-device-actions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#bulk-device-actions&quot;&gt;Bulk Device Actions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ve now enabled the ability to perform bulk actions on devices in FlowFuse. This is particularly useful for managing large numbers of devices, where you might want to update the settings, or delete multiple devices at once.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Bulk Device Actions feature in FlowFuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/bulk-delete-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new Bulk Device Actions feature in FlowFuse&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For now, we just support bulk delete, but we&#39;re planning to add &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2381&quot;&gt;more bulk actions&lt;/a&gt; in the very near future.&lt;/p&gt;
&lt;h3 id=&quot;and-much-more...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#and-much-more...&quot;&gt;And Much More...&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For a full list of everything that went into our 2.7 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.7.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install using &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.7, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/08/flowfuse-2-7-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/</id>
        <title>How to Set Up SSO LDAP for Node-RED</title>
        <summary>Step-by-step guide on setting up SSO LDAP for your self-hosted FlowFuse platform</summary>
        <updated>2024-07-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;A few days ago, we published a &lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/&quot;&gt;blog&lt;/a&gt; explaining SSO and how to set up SAML for your self-hosted FlowFuse. Now, in this guide, we will walk you through the process of setting up SSO with LDAP for your self-hosted FlowFuse. We will use OpenLDAP as the provider and cover everything from introducing LDAP, how it works, installing and configuring OpenLDAP, managing users (create, delete, update), and finally setting up FlowFuse for SSO with LDAP.&lt;/p&gt;
&lt;h2 id=&quot;understanding-ldap-sso%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#understanding-ldap-sso%3F&quot;&gt;Understanding LDAP SSO?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;what-is-ldap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#what-is-ldap&quot;&gt;What is LDAP&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;LDAP (Lightweight Directory Access Protocol) is a protocol used to access and manage directory information. In the context of network administration, a directory service acts as a specialized database that stores and organizes information about users, devices, and other resources. Think of it as a digital phonebook for your network, allowing centralized management and efficient access to information.&lt;/p&gt;
&lt;p&gt;LDAP enables applications and services to query, add, update, and delete directory entries stored on LDAP servers. It simplifies identity management by enabling easy authentication, authorization, and quick access to information across distributed systems.&lt;/p&gt;
&lt;h3 id=&quot;how-ldap-sso-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#how-ldap-sso-works&quot;&gt;How LDAP SSO works&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Authentication Request:&lt;/strong&gt; A user attempts to access a service or application that requires authentication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSO Initiation:&lt;/strong&gt; The application forwards the authentication request to the Identity Provider (IdP) configured with LDAP, such as OpenLDAP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LDAP Authentication:&lt;/strong&gt; The IdP (LDAP server) verifies the user&#39;s credentials against its directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication Response:&lt;/strong&gt; If the credentials are valid, the LDAP server sends an authentication response (usually a token or assertion) back to the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access Granted:&lt;/strong&gt; The application grants access to the user based on the authentication response received from the LDAP server.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;setting-up-sso-ldap-for-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#setting-up-sso-ldap-for-flowfuse&quot;&gt;Setting up SSO LDAP for FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we proceed, ensure that FlowFuse is deployed on your server with an Enterprise license and you have ssh connection with it so that you can run commands on the server. If you haven&#39;t installed it yet, please check out our &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;documentation on installing FlowFuse&lt;/a&gt; or our blog on &lt;a href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/&quot;&gt;deploying FlowFuse on Ubuntu with Docker&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;installing-and-configuring-openldap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#installing-and-configuring-openldap&quot;&gt;Installing and Configuring OpenLDAP&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Throughout this section, we will install and configure OpenLDAP on your Ubuntu server. Make sure to replace the commands and configs with your details. If you are using a different distribution, you can follow other resources available on the internet for installation and configuration, as well as managing of users.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set the hostname for your LDAP server:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-62&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-62&quot; class=&quot;language-bash&quot;&gt;hostnamectl set-hostname ldap.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;your-domain&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;.com&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-62&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the server IP to &lt;code&gt;/etc/hosts&lt;/code&gt;:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-68&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-68&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;your_server_ip&gt; ldap.&amp;lt;your-domain&gt;.com&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/hosts&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-68&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install OpenLDAP and related utilities:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-74&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-74&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;apt&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; slapd ldap-utils&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-74&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set an administrator password for LDAP during installation and confirm it in the next prompt.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to set the administrator password&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to set the administrator password while installation&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Ldap-Server-Admin-Password-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to conform the administrator password&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to conform the administrator password&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Confirm-Ldap-Admin-Passsword-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Reconfigure the slapd package:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-93&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-93&quot; class=&quot;language-bash&quot;&gt;dpkg-reconfigure slapd&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-93&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When asked to omit server configuration, select ‘NO’&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to omit the server configuration&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to omit the server configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Cofiguring-slapd-ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;
&lt;p&gt;Configure the base DN (Distinguished Name) for your LDAP directory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use your domain name to construct the base DN. For example, if your domain is &lt;code&gt;my-flows.site&lt;/code&gt;, the base DN would be &lt;code&gt;dc=my-flows,dc=site&lt;/code&gt; and press &#39;ENTER&#39; to confirm.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to enter your domain to construct the base DN&quot; alt=&quot;Screenshot of prompt asking to enter your domain to construct the base DN&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/prompt-for-domain.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provide a name for your organization, which will also be part of the base DN and press &#39;Enter.&#39;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to enter your org name&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to enter your org name&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/prompt-for-org.jpeg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;Enter the Administrator password for your LDAP directory.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to set the administrator password&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to set the administrator password&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Ldap-Server-Admin-Password-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;Confirm the password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of prompt asking to conform the administrator password&quot; alt=&quot;&amp;quot;Screenshot of prompt asking to conform the administrator password&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Confirm-Ldap-Admin-Passsword-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;When asked to remove the database when slapd is purged, select ‘NO’.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the prompt asking to remove the database when slapd is purged&quot; alt=&quot;&amp;quot;Screenshot of the prompt asking to remove the database when slapd is purged&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Database-Removal-Slapd-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;Select ‘Yes’ to remove the old database to create room for a new database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the prompt asking to remove the old database&quot; alt=&quot;&amp;quot;Screenshot of the prompt asking to remove the old database&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Select-Yes-Move-Old-Databases-Slapd-Ubuntu.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Edit the main OpenLDAP configuration file:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-178&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-178&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/ldap/ldap.conf&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-178&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;14&quot;&gt;
&lt;li&gt;Uncomment the lines beginning with “BASE” and “URI”, for example, my domain is &lt;code&gt;my-flows.site&lt;/code&gt;, we have updated the file as below, but you have to update it according to your domain:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;BASE `dc=my-flows,dc=site.`
URI `ldap://ldap.my-flows.site.`
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;adding%2C-updating%2C-and-deleting-groups-and-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#adding%2C-updating%2C-and-deleting-groups-and-users&quot;&gt;Adding, Updating, and Deleting Groups and Users&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;adding-groups-and-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#adding-groups-and-users&quot;&gt;Adding Groups and Users&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a file for the base groups and open the editor:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-198&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-198&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; groups.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-198&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following content to &lt;code&gt;groups.ldif&lt;/code&gt;, which will create the &lt;code&gt;users&lt;/code&gt; group, make sure when you create a new group the gidNumber and ou is unique:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dn: ou=users,dc=my-flows,dc=site
objectClass: organizationalUnit
ou: users
gidNumber: 7000
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the groups to the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-210&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-210&quot; class=&quot;language-bash&quot;&gt;ldapadd &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; groups.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-210&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create  a password for the user and store the encrypted password:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-218&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-218&quot; class=&quot;language-bash&quot;&gt;Slappasswd &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-218&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Create a file for the user:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-224&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-224&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; user.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-224&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following content to user.ldif. Replace the placeholders with actual values for &lt;code&gt;uid&lt;/code&gt;, &lt;code&gt;sn&lt;/code&gt;, &lt;code&gt;givenName&lt;/code&gt;,&lt;code&gt;displayName&lt;/code&gt;,&lt;code&gt;cn&lt;/code&gt; ,&lt;code&gt;gecos&lt;/code&gt; , &lt;code&gt;homeDirectory&lt;/code&gt;, and set userPassword to the password generated earlier. Ensure each user has a unique &lt;code&gt;uidNumber&lt;/code&gt;, and you can keep the gidNumber the same if users belong to the same primary group&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dn: uid=sumit,ou=users,dc=my-flows,dc=site
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: sumit
sn: shinde
givenName: sumit
cn: sumit shinde
displayName: sumit shinde
uidNumber: 1000
gidNumber: 7000
userPassword: {SSHA}uQVjd8MLaJ7AXEd/grqViuKnk9tNojdy
gecos: sumit shinde
loginShell: /bin/bash
homeDirectory: /home/sumit
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save and exit the configuration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the user to the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-241&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-241&quot; class=&quot;language-bash&quot;&gt;ldapadd &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; user.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-241&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;updating-groups-and-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#updating-groups-and-users&quot;&gt;Updating Groups and Users&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a file for the user update:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-252&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-252&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; user_update.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-252&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following content to &lt;code&gt;user_update.ldif&lt;/code&gt; to update the user&#39;s details (e.g., changing the display name):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dn: uid=sumit,ou=users,dc=my-flows,dc=site
changetype: modify
replace: displayName
displayName: Sumit Rupesh Shinde
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save and exit the configuration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply the update to the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-269&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-269&quot; class=&quot;language-bash&quot;&gt;ldapmodify &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; user_update.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-269&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a file for the group update:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-275&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-275&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; group_update.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-275&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following content to &lt;code&gt;group_update.ldif&lt;/code&gt; to update the group&#39;s details (e.g., changing the organizational unit name):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dn: ou=users,dc=my-flows,dc=site
changetype: modify
replace: ou
ou: staff
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save and exit the configuration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply the update to the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-292&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-292&quot; class=&quot;language-bash&quot;&gt;ldapmodify &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; group_update.ldif&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-292&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;deleting-groups-and-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#deleting-groups-and-users&quot;&gt;Deleting Groups and Users&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Delete a user from the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-303&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-303&quot; class=&quot;language-bash&quot;&gt;ldapdelete &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;uid=sumit,ou=users,dc=my-flows,dc=site&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-303&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Delete a group from the LDAP directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-309&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-309&quot; class=&quot;language-bash&quot;&gt;ldapdelete &lt;span class=&quot;token parameter variable&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;cn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;admin,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-flows,dc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;site &lt;span class=&quot;token parameter variable&quot;&gt;-W&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ou=users,dc=my-flows,dc=site&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-309&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;configuring-and-enabling-sso-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#configuring-and-enabling-sso-in-flowfuse&quot;&gt;Configuring and Enabling SSO in FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;To configure FlowFuse with SSO, make sure you are logged in as an administrator.&lt;/li&gt;
&lt;li&gt;Go to Admin settings by clicking on the profile icon in the top-right corner and then selecting &amp;quot;Admin settings&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the admin settings option in the profile icon&quot; alt=&quot;&amp;quot;Screenshot showing the admin settings option in the profile icon&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/admin-setting-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on &amp;quot;Settings&amp;quot; from the left sidebar and switch to the SSO section.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the sso section in the admin settings&quot; alt=&quot;&amp;quot;Screenshot showing the sso section in the admin settings&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/setting&#39;s-sso-setting-section.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click on the top-right &amp;quot;Create SSO configuration&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the &#39;create sso configuration&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;create sso configuration&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/create-sso-config-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Enter the name for your configuration, then enter the domain with &lt;code&gt;@&lt;/code&gt; prefix and select the &amp;quot;LDAP&amp;quot; option. Click on the &amp;quot;Create configuration&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the initial form to create ldap sso configuration&quot; alt=&quot;&amp;quot;Screenshot showing the initial form to create ldap sso configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sso-config-ldap.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;In the next form, in the server field enter &lt;code&gt;your-server-ip:389&lt;/code&gt;. 389 is the default port for LDAP but make sure to check it. If you are going to enable TLS, replace the port with 636.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the advance form to create ldap sso configuration&quot; alt=&quot;&amp;quot;Screenshot showing the advance form to create ldap sso configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ldap-advance-config-tag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Enter the the bind DN into the username field.&lt;/li&gt;
&lt;li&gt;Enter the password for the LDAP administrator in the password field.&lt;/li&gt;
&lt;li&gt;Enter the Base DN. For example, if your domain is &lt;code&gt;my-flows.site&lt;/code&gt;, the Base DN will be &lt;code&gt;dc=my-flows,dc=site&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click on the &amp;quot;Update configuration&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;signing-in-using-sso&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#signing-in-using-sso&quot;&gt;Signing in Using SSO&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To sign in using SSO, users of your self-hosted FlowFuse must have a FlowFuse account created with an email ID associated with the domain configured with SSO. For more information, refer to &lt;a href=&quot;https://flowfuse.com/docs/admin/user_management/#creating-new-users&quot;&gt;creating users in FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your platform in the browser. Enter the username in the username/email field.&lt;/li&gt;
&lt;li&gt;Click on &amp;quot;Login&amp;quot;.&lt;/li&gt;
&lt;li&gt;Then enter the password set in the LDAP directory for that user.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Note: Admin users will still be able to log in with their original FlowFuse username/password - this ensures they don&#39;t get locked out of the platform if there is a problem with the SSO configuration&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we covered how to set up SSO with LDAP for your self-hosted FlowFuse platform using OpenLDAP. We installed and configured OpenLDAP, learned to managed groups and users, and configured SSO within FlowFuse. This setup enhances security by centralizing user authentication and simplifies access across applications, ensuring efficient user management in your FlowFuse deployment.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/dashboard-new-charts/</id>
        <title>New Charts Available in FlowFuse Dashboard</title>
        <summary>Our most recent update for FlowFuse Dashboard has introduced Pie, Donut and Grouped Bar charts, and plenty more.</summary>
        <updated>2024-07-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/dashboard-new-charts/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It&#39;s been a while coming, but we&#39;ve finally introduced a new set of chart types to FlowFuse Dashboard. We&#39;ve added Pie, Donut and Grouped (Stacks and Side-by-Side) Bar charts to the UI Chart node. We&#39;ve also shipped plenty of other improvements and fixes in this release, so let&#39;s dive in.&lt;/p&gt;
&lt;h2 id=&quot;grouped-bar-charts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#grouped-bar-charts&quot;&gt;Grouped Bar Charts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We now have the option &amp;quot;Group By&amp;quot; available when building Bar Charts, with the options &amp;quot;Stacks&amp;quot; and &amp;quot;Side-by-Side&amp;quot;. This allows you to group data in a more meaningful way, and is particularly useful when comparing multiple data sets.&lt;/p&gt;
&lt;h3 id=&quot;stacks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#stacks&quot;&gt;Stacks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a stacked bar chart with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-bar-grouped-finance-stacks.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a stacked bar chart with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;side-by-side&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#side-by-side&quot;&gt;Side-by-Side&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing a side-by-side grouped bar chart with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-bar-grouped-finance.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing a side-by-side grouped bar chart with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;pie-%26-donut-charts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#pie-%26-donut-charts&quot;&gt;Pie &amp;amp; Donut Charts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Radial charts are now available in Dashboard, with the introduction of Pie and Donut charts. These are particularly useful when you want to show the proportion of a single data set.&lt;/p&gt;
&lt;p&gt;If you&#39;re using multiple &amp;quot;Series&amp;quot; here, then you&#39;ll get multiple nested radial charts, which can be particularly useful when comparing multiple data sets.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new Pie and Donut charts available with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-pie-doughnut.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new Pie and Donut charts available with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;general-chart-changes-%26-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#general-chart-changes-%26-improvements&quot;&gt;General Chart Changes &amp;amp; Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;breaking-changes---bar-charts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#breaking-changes---bar-charts&quot;&gt;Breaking Changes - Bar Charts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the introduction of the new chart types, we&#39;ve generalised the key mapping features for charts. Previously, Bar Charts were using the &amp;quot;Series&amp;quot; property to define how data is rendered onto the x-axis. In hindsight, this didn&#39;t really make any sense, it should be the &amp;quot;X&amp;quot; property that defines the data used on the x-axis, so we&#39;ve corrected that going forward, but it did mean introducing a breaking change. We don&#39;t do this lightly, but in this case, it was necessary to ensure the charting experience is consistent across all chart types.&lt;/p&gt;
&lt;p&gt;It does however mean that Bar Charts created in &lt;code&gt;1.13.0&lt;/code&gt; or below will need to be updated to reflect this. You just need to set &amp;quot;X&amp;quot; to whatever you have in the &amp;quot;Series&amp;quot; property, and then set &amp;quot;Series&amp;quot; to &amp;quot;None&amp;quot;.&lt;/p&gt;
&lt;h3 id=&quot;mapping-your-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#mapping-your-data&quot;&gt;Mapping Your Data&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;series&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#series&quot;&gt;Series&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This property is now, consistently, how you want to group your data. If a new &lt;code&gt;msg&lt;/code&gt; is coming in, and a property on that &lt;code&gt;msg&lt;/code&gt; defines its group, then you can set &amp;quot;Series&amp;quot; to something like &lt;code&gt;msg.myCategory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If a single data point needs to plot multiple points/bars onto a chart, then you can use the &amp;quot;JSON&amp;quot; type here, and list the different properties you want to plot, one for each category.&lt;/p&gt;
&lt;p&gt;For Radial charts (Pie &amp;amp; Donut), having multiple series would provide multiple, nested radial charts.&lt;/p&gt;
&lt;h4 id=&quot;x&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#x&quot;&gt;X&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;With this, we define which property (or &lt;em&gt;properties&lt;/em&gt; if a single piece of data needs to plot multiple points/bars) we want to plot on the x-axis.&lt;/p&gt;
&lt;p&gt;Note that on Radial charts (Pie &amp;amp; Donut), this is the value that defines the label of the segment.&lt;/p&gt;
&lt;h4 id=&quot;y&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#y&quot;&gt;Y&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Which property should be used to define the y-axis value, i.e. height of the bar or the y-coordinate of a point on a scatter chart.&lt;/p&gt;
&lt;p&gt;Note that on Radial charts (Pie &amp;amp; Donut), this is the value that defines the size of the segment.&lt;/p&gt;
&lt;h4 id=&quot;example%3A-plotting-star-wars-character-heights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#example%3A-plotting-star-wars-character-heights&quot;&gt;Example: Plotting Star Wars Character Heights&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;a href=&quot;https://swapi.dev/&quot;&gt;Star Wars API&lt;/a&gt; is a free, open API that provides data on the Star Wars universe, an example API call can return details about particular characters, and the response is as follows:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-84&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-84&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Luke Skywalker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;172&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;mass&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;77&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;hair_color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blond&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;skin_color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fair&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;eye_color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;birth_year&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;19BBY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;gender&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;male&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-84&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We can configure a chart with the following &amp;quot;Mapping&amp;quot; options:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example mapping of data to a UI Chart for data coming from the Star Wars API&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-bar-sw-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Example mapping of data to a UI Chart for data coming from the Star Wars API&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;and this would then be the resulting chart:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example bar chart showing heights of Star Wars characters&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-bar-sw.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Example bar chart showing heights of Star Wars characters&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Note, the chart takes in all of the data sent to it, uses the &lt;code&gt;name&lt;/code&gt; field to define where on the x-axis the data should be plotted, and the &lt;code&gt;height&lt;/code&gt; field to define the height of the bar (the y-axis).&lt;/p&gt;
&lt;p&gt;You can read more about this example, and access the flow itself in our documentation &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-chart.html#bar-charts&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;live-dashboard-demo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#live-dashboard-demo&quot;&gt;Live Dashboard Demo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of our new interactive Dashboard to demonstrate how charts render in FlowFuse Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-interactive-docs.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of our new interactive Dashboard to demonstrate how charts render in FlowFuse Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With the new release also comes a new &lt;a href=&quot;https://dashboard-demos.flowfuse.cloud/dashboard/charts-example&quot;&gt;Public Demo Dashboard&lt;/a&gt; that we&#39;ve made available for all to use and play with.&lt;/p&gt;
&lt;p&gt;You can try it out, and interact with a range of different chart types, including the new Pie, Donut and Grouped Bar charts. We&#39;ll also be extending this soon to cover the full range of widgets available in FlowFuse Dashboard.&lt;/p&gt;
&lt;p&gt;If you want more technical detail, you can also check out our online documentation &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-chart.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#what-else-is-new%3F&quot;&gt;What else is new?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can find the full 1.14.0 Release Notes &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v1.14.0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just to highlight a few, particularly valuable, updates and fixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Button Group - Now supports &lt;code&gt;msg.enabled&lt;/code&gt; to enable/disable the widget.&lt;/li&gt;
&lt;li&gt;UI Form - Now supports &lt;code&gt;msg.enabled&lt;/code&gt; to enable/disable the widget.&lt;/li&gt;
&lt;li&gt;UI Button - Color customisation now available, without needing to write overriding CSS.&lt;/li&gt;
&lt;li&gt;UI Switch - Fix missing &lt;code&gt;msg.topic&lt;/code&gt; when setting the topic to a static string.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/dashboard-new-charts/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Work has already begun on the next release, &lt;code&gt;1.15.0&lt;/code&gt;, you can see what items we have queued up &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;here&lt;/a&gt;, if you&#39;ve got any feedback or suggestions, please do let us know, and feel free to open new issues on our &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/</id>
        <title>Evolution of Technology: Impact on Job Roles and Companies</title>
        <summary>The Role of FlowFuse in the Modern Technological Landscape</summary>
        <updated>2024-07-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Throughout history, technology has continuously transformed industries, job roles, and entire companies. While these changes often evoke fear and resistance, they also create new jobs, opportunities for innovation and growth. This post will explore how historical technological advancements have reshaped both individual job roles and entire companies, examine current trends like AI and low-code tools, and discuss the critical importance of adaptability for both individuals and businesses in navigating technological disruption, Importantly, we will address the pressing question of our time: &lt;em&gt;&lt;strong&gt;&amp;quot;How can AI and low-code tools both enhance and challenge human capabilities, creativity, and the job market, and is this the next frontier in manufacturing or just hype&amp;quot;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;historical-examples-of-technological-disruption-and-business-impact&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/#historical-examples-of-technological-disruption-and-business-impact&quot;&gt;Historical Examples of Technological Disruption and Business Impact&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Industrial Revolution serves as a powerful example of how technological advancements disrupted entire industries and reshaped business landscapes. In the late 18th and early 19th centuries, mechanized manufacturing replaced traditional artisanal crafts and manual labor. Companies that embraced these new technologies, such as textile mills and steam-powered factories, experienced unprecedented growth and profitability. Conversely, businesses that clung to outdated methods faced decline or closure as they struggled to compete with more efficient and scalable production methods.&lt;/p&gt;
&lt;p&gt;The advent of the automobile in the early 20th century brought about another wave of technological disruption. As cars replaced horse-drawn carriages, companies in the transportation and manufacturing sectors had to adapt or risk becoming obsolete. Established businesses that successfully transitioned to automotive manufacturing thrived, while those that resisted change faced significant challenges. For instance, companies that continued to produce horse-drawn carriages struggled to maintain market relevance and profitability.&lt;/p&gt;
&lt;p&gt;The digital revolution of the late 20th century further accelerated technological disruption across industries. The introduction of computers, the internet, and digital communication transformed how businesses operated, communicated, and conducted commerce. Companies that embraced digital technologies gained competitive advantages in efficiency, customer engagement, and global market reach. In contrast, businesses that resisted digital transformation struggled to keep pace with rapidly evolving consumer expectations and market dynamics.&lt;/p&gt;
&lt;h2 id=&quot;current-trends%3A-ai%2C-low-code-tools%2C-and-strategic-adaptation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/#current-trends%3A-ai%2C-low-code-tools%2C-and-strategic-adaptation&quot;&gt;Current Trends: AI, Low-Code Tools, and Strategic Adaptation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today, we are witnessing a new era of technological disruption driven by artificial intelligence (AI) and low-code/no-code development platforms. AI technologies are revolutionizing business operations by automating routine tasks, analyzing vast amounts of data, and enhancing decision-making processes. Companies that strategically integrate AI into their operations can optimize productivity, personalize customer experiences, and gain valuable insights into market trends and consumer behavior. However, businesses that hesitate to adopt AI risk falling behind competitors who leverage these technologies to innovate and drive business growth.&lt;/p&gt;
&lt;p&gt;Low-code and no-code development platforms represent another transformative trend reshaping how companies approach software development and innovation. These platforms empower business users and citizen developers to create applications and automate workflows with minimal coding knowledge. By democratizing software development, low-code tools enable faster application deployment, greater agility in responding to market demands, and enhanced collaboration between IT and business teams. Companies that embrace low-code platforms like Node-RED can accelerate digital transformation initiatives, streamline business processes, and drive innovation across the organization.&lt;/p&gt;
&lt;p&gt;Furthermore, AI and low-code tools disrupt traditional job roles and create new opportunities across various fields. Roles such as AI Integration Specialists, Data Scientists, and Machine Learning Engineers, prompt engineers are increasingly in demand as companies seek to enhance efficiency and productivity. Similarly, the adoption of low-code tools like Node-RED is leading to the creation of positions such as Automation Engineers, IoT Developers, and Integration specialists, and Node-RED is becoming a standard requirement in jobs across manufacturing and IoT industries.&lt;/p&gt;
&lt;h2 id=&quot;the-importance-of-adaptability-and-strategic-vision&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/#the-importance-of-adaptability-and-strategic-vision&quot;&gt;The Importance of Adaptability and Strategic Vision&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Historically, individuals and businesses that fail to adapt to technological change or embrace innovation risk becoming obsolete in competitive markets. A notable example is Nokia, once a dominant player in the mobile phone industry. Nokia initially thrived by pioneering mobile technology and establishing a strong market presence. However, the company&#39;s reluctance to embrace the shift to smartphones and its adherence to outdated business models ultimately led to its decline. In contrast, competitors like Apple and Samsung seized opportunities in the smartphone market, leveraging innovation and consumer-centric strategies to surpass Nokia in market share and profitability. There are numerous such examples, one being Xerox. Watch this short video where Steve Jobs, founder of Apple, explains &lt;a href=&quot;https://www.youtube.com/watch?v=X3NASGb5m8s&amp;amp;t=2s&quot;&gt;Why Xerox failed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The strategic adoption of AI and low-code tools is critical for maintaining competitive advantage and driving sustainable growth. While concerns about AI ethics and reliability are valid, businesses that implement AI technologies responsibly can enhance operational efficiency, improve decision-making processes, and deliver superior customer experiences. Similarly, companies that embrace low-code development platforms can accelerate time-to-market for new applications, reduce development costs, and empower business units to innovate and iterate more rapidly. Amazon, for instance, exemplifies this adaptability by evolving from an online bookstore to a global leader in e-commerce and cloud computing through strategic technology integration.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-the-perfect-combo-of-low-code-and-ai&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/#flowfuse%3A-the-perfect-combo-of-low-code-and-ai&quot;&gt;FlowFuse: The perfect combo of Low-code and AI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is a cloud-based platform for Node-RED, a popular low-code tool. It enhances Node-RED with real-time collaboration, version control, and remote edge device programming.&lt;/p&gt;
&lt;p&gt;With the capability to integrate over 5000 applications, protocols, and technologies, FlowFuse empowers businesses to innovate and streamline operations.
Recently, FlowFuse has integrated AI features like the &lt;a href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/&quot;&gt;Function GPT&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/blog/2023/11/chatgpt-gpt/&quot;&gt;Node-RED Builder&lt;/a&gt; and the &lt;a href=&quot;https://flowfuse.com/changelog/2024/07/flowfuse-assistant/&quot;&gt;FlowFuse Expert&lt;/a&gt;. These tools allow users to automate flow creation, significantly boosting productivity. This combination of low-code development and AI positions FlowFuse as a transformative tool for modern businesses.&lt;/p&gt;
&lt;p&gt;Manufacturing companies are already adopting these advanced features to optimize their operations and stay competitive. Tech professionals should also prepare to leverage these tools to harness the full potential of AI and low-code development.&lt;/p&gt;
&lt;p&gt;FlowFuse provides businesses, particularly those in the manufacturing sector, with a revolutionary solution powered by artificial intelligence and effective low-code platforms that make operations more efficient and increase output. This combination promotes quick innovation and flexibility, essential for maintaining a competitive edge in the era of Industry 4.0. FlowFuse&#39;s strong integration features guarantee the ability to expand successfully and maintain smooth connections across various applications, enabling manufacturing companies to improve their operations, enhance teamwork, and provide outstanding products and services.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/evolution-of-technology-impact-on-job-roles-and-companies/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Technology has always driven change, disrupting traditional models and opening new growth avenues. From the Industrial Revolution to today&#39;s AI and low-code tools, adaptability, strategic vision, and innovation remain key to success. By embracing emerging technologies and a forward-thinking mindset, individuals and companies can lead in innovation, customer focus, and sustainable growth in a competitive global economy.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/</id>
        <title>How to Set Up SSO SAML for Node-RED</title>
        <summary>Step-by-step guide on setting up SSO SAML for your self-hosted FlowFuse platform</summary>
        <updated>2024-07-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;SSO plays a crucial role in modern enterprise environments by simplifying user authentication across multiple applications. At FlowFuse, we recognize the significance of SSO and offer robust support for integrating it with your self-hosted platform. In this comprehensive guide, we will focus on configuring SSO SAML, specifically using Google as the Identity Provider (IdP). We also support SSO with LDAP. For more information, refer to &lt;a href=&quot;https://flowfuse.com/docs/admin/sso/ldap/&quot;&gt;Setting up LDAP SSO for your Self-Hosted FlowFuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-sso%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#what-is-sso%3F&quot;&gt;What is SSO?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Single Sign-On (SSO) is a technology that allows users to access multiple applications or services with one set of login credentials. When a user logs in to one central system, known as the Identity Provider (IdP) such as Google, Microsoft Azure AD, or Okta, it authenticates the user and creates a session token. This token is then used to access other connected applications without requiring the user to log in again. The IdP verifies the token and shares the authentication information with other applications, ensuring secure and seamless access across multiple platforms. This reduces the need to remember multiple passwords and enhances security by centralizing authentication.&lt;/p&gt;
&lt;h2 id=&quot;understanding-saml&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#understanding-saml&quot;&gt;Understanding SAML&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SAML (Security Assertion Markup Language) is a protocol used in SSO scenarios to exchange authentication and authorization data between an Identity Provider (IdP) and a Service Provider (SP). Here’s how it works step-by-step:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the working process of SSO SAML&quot; alt=&quot;&amp;quot;Image showing the working process of SSO SAML&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/SAML-SSO.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Request&lt;/strong&gt;: A user attempts to access a service or application that is protected by SAML-based SSO.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirect to IdP&lt;/strong&gt;: The Service Provider (SP), recognizing that the user needs authentication, redirects them to the Identity Provider (IdP).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Authentication&lt;/strong&gt;: The IdP prompts the user to authenticate themselves. This authentication can involve various methods, such as username/password, multi-factor authentication (MFA), or other authentication mechanisms supported by the IdP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generating SAML Assertion&lt;/strong&gt;: Upon successful authentication, the IdP generates a SAML assertion. This assertion contains information about the user&#39;s identity (like username, email) and any attributes or roles associated with the user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sending SAML Assertion&lt;/strong&gt;: The IdP sends this SAML assertion back to the Service Provider (SP), typically through the user&#39;s browser. The assertion is digitally signed by the IdP to ensure its authenticity and integrity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Assertion Validation&lt;/strong&gt;: The Service Provider (SP) receives the SAML assertion. It validates the assertion to ensure it comes from a trusted IdP and that the assertions&#39; contents are accurate and have not been tampered with.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Granting Access&lt;/strong&gt;: If the assertion is valid, the SP grants access to the user based on the information in the SAML assertion. This allows the user to access the protected application or service without needing to provide separate credentials to the SP.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;benefits-of-using-sso-in-the-workspace&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#benefits-of-using-sso-in-the-workspace&quot;&gt;Benefits of Using SSO in the Workspace&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Improved User Experience&lt;/strong&gt;: Users only need to remember one set of credentials, making the login process simpler and reducing password fatigue. For instance, In a manufacturing environment, employees often need to access multiple systems, such as Node-RED, ERP systems, and quality control applications. With SSO, they only need to remember one set of credentials, simplifying the login process and reducing password fatigue.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simplified Management&lt;/strong&gt;: Administrators can manage user access and permissions from a single platform, making it easier to onboard new employees and revoke access when someone leaves. This centralized management ensures that only authorized personnel can access the application flows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increased Security&lt;/strong&gt;: Centralized authentication via SSO reduces the risk of weak or reused passwords, allowing for the implementation of stronger security policies. This is critical in a workspace where sensitive data and operational systems must be protected against unauthorized access.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Productivity&lt;/strong&gt;: SSO allows employees to log in once and gain access to all necessary applications, saving time and reducing interruptions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;setting-up-sso-for-your-self-hosted-flowfuse-platform&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#setting-up-sso-for-your-self-hosted-flowfuse-platform&quot;&gt;Setting up SSO For Your Self-Hosted FlowFuse Platform&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before proceeding, ensure you have deployed FlowFuse on your server with an Enterprise license and configured it with email. Without email configuration, the SSO setup option won&#39;t appear in your FlowFuse.Furthermore, Make sure you have a &lt;a href=&quot;https://www.youtube.com/watch?v=Rc7BT7PDqFs&quot;&gt;Google Workspace account created&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=JIOaLKsz2R0&quot;&gt;verified your domain&lt;/a&gt; within Google Workspace. FlowFuse supports other providers for SAML SSO as well; check our &lt;a href=&quot;https://flowfuse.com/docs/admin/sso/saml/#providers&quot;&gt;documentation on supported providers&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t deployed FlowFuse yet, refer to our &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;documentation on installing FlowFuse&lt;/a&gt; or our blog on &lt;a href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/&quot;&gt;deploying FlowFuse on Ubuntu with Docker&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;configuring-sso-in-your-self-hosted-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#configuring-sso-in-your-self-hosted-flowfuse&quot;&gt;Configuring SSO in your Self-Hosted FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;To configure FlowFuse with SSO, make sure you are logged in as an administrator.&lt;/li&gt;
&lt;li&gt;Go to Admin settings by clicking on the profile icon in the top-right corner and then selecting &amp;quot;Admin settings&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the admin settings option in the profile icon&quot; alt=&quot;&amp;quot;Screenshot showing the admin settings option in the profile icon&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/admin-setting-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on &amp;quot;Settings&amp;quot; from the left sidebar and switch to the SSO section.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of platform showing the &#39;admin settings&#39; &#39;SSO&#39; tab option&quot; alt=&quot;&amp;quot;Screenshot of platform showing the &#39;admin settings&#39; &#39;SSO&#39; tab option&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/setting&#39;s-sso-setting-section.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click on the top-right &amp;quot;Create SSO configuration&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of platform showing the &#39;Creating configuration&#39; button&quot; alt=&quot;&amp;quot;Screenshot of platform showing the &#39;Creating configuration&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/create-sso-config-button.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Enter a name for your configuration, then enter the domain that the platform will use for SSO and select &amp;quot;SAML&amp;quot; option and click on &amp;quot;create configuration&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of platform form for creating sso configuration&quot; alt=&quot;&amp;quot;Screenshot of platform form for creating sso configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sso-config-initial-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;In the next tab, you&#39;ll find the ACS URL and Entity ID. Copy and save them somewhere in the notepad.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of advance sso form showing the ACS URL and Entity ID and other feilds for configuration&quot; alt=&quot;&amp;quot;Screenshot of advance sso form showing the ACS URL and Entity ID and other feilds for configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sso-config-next-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Tick &amp;quot;Manage roles using group assertions&amp;quot; if needed. If enabled, keep the Group Assertion Name to its default value and select the team scope:
&lt;ul&gt;
&lt;li&gt;&amp;quot;Apply to selected teams&amp;quot; restricts management to the provided list of groups, For adding the list refer to &lt;a href=&quot;https://flowfuse.com/docs/admin/sso/saml/#saml-groups-configuration&quot;&gt;SAML Groups configuration&lt;/a&gt;, suitable for shared-tenancy platforms like FlowFuse Cloud.&lt;/li&gt;
&lt;li&gt;&amp;quot;Apply to all teams&amp;quot; allows SAML groups to manage all teams, suitable for a self-hosted installation with a single SSO configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click on &amp;quot;Update configuration&amp;quot;, we will back to update this configuration with our configuration provided by our Google workpsace later.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;creating-the-saml-app-in-google-workspace.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#creating-the-saml-app-in-google-workspace.&quot;&gt;Creating the SAML APP in Google Workspace.&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open the main menu from the top-right corner by clicking on menu icon.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;web and mobile apps&#39; option in the sidebar in the Google workspace admin console&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;web and mobile apps&#39; option in the sidebar in the Google workspace admin console&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/main-menu&#39;s-web-and-mobile-apps-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Click on the &amp;quot;Apps&amp;quot; icon, which expands additional choices. Then click on the &amp;quot;Web and mobile apps.&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then the new tab opens, click on to the &amp;quot;Add app&amp;quot; from the top.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Add custom SAML apps&#39; option in the Google workspace admin console&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Add app&#39; and &#39;Add custom SAML apps&#39; option in the Google workspace admin console&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/add-custom-saml-apps-option.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;The options open select the &amp;quot;Add custom SAML apps.&amp;quot;&lt;/li&gt;
&lt;li&gt;Enter the app name description and upload an icon for the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the form asking for app information for we are going to create the SAML app configuration in the Google workspace admin console&quot; alt=&quot;&amp;quot;Screenshot showing the form asking for app information for we are going to create the SAML app configuration in the Google workspace admin console&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-to-add-app-info.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Now copy your Copy the SSO URL, entity ID and certificate or you can simply download it in the one file by clicking on the Download metadata button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot configuration provided the Google workspace admin console for SSO SAML&quot; alt=&quot;&amp;quot;Screenshot configuration provided the Google workspace admin console for SSO SAML&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/config-details-for-sso.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Click on the continue.&lt;/li&gt;
&lt;li&gt;In the next tab, enter the ACS URL and entity id provided by your self-hosted flowfuse platform.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot form asking for the configuration detailes provided by your self-hosted FlowFuse&quot; alt=&quot;&amp;quot;Screenshot form asking for the configuration detailes provided by your self-hosted FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-to-add-the-config-provided-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;
&lt;p&gt;Enter the start URL as &lt;code&gt;forge.&amp;lt;your-domain&amp;gt;.com&lt;/code&gt;, we are specify that after successfull sign in the user should be redirected to this url.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, click on &amp;quot;Continue&amp;quot; button and then click on &amp;quot;finish&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;updating-the-flowfuse-sso-configuration-and-enabling-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#updating-the-flowfuse-sso-configuration-and-enabling-it&quot;&gt;Updating the FlowFuse SSO configuration and enabling it&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have created the SAML app in the workspace, we need to update the FlowFuse configuration and connect it to the app created in the workspace to enable SSO.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the SSO section of the admin settings in your self-hosted FlowFuse platform. Click on the three-dot icon located at the right corner of the added configuration and select &amp;quot;Edit.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing three dot icons in your self-hosted FlowFuse&quot; alt=&quot;&amp;quot;Screenshot showing three dot icons in your self-hosted FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-sso-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Add the copied values for the fields: Identity Provider Single Sign-On URL, Identity Provider Issuer ID / URL, and X.509 Certificate Public Key provided by the provider. I instructed you in the above section to copy or download them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the form updated with configuration provided by Google workspace&quot; alt=&quot;&amp;quot;Screenshot showing the form updated with configuration provided by Google workspace&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sso-config-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on the &amp;quot;Active&amp;quot; option to enable the SSO in the same form.&lt;/li&gt;
&lt;li&gt;Click on &amp;quot;Update configuration&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;signing-in-using-sso&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#signing-in-using-sso&quot;&gt;Signing in Using SSO&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To sign in using SSO, users of your self-hosted FlowFuse must have a FlowFuse account created with an email ID associated with the domain configured with SSO. For more information, refer to &lt;a href=&quot;https://flowfuse.com/docs/admin/user_management/#creating-new-users&quot;&gt;creating users in FlowFuse&lt;/a&gt;. Additionally, the user must already be logged in with that email in the browser.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your platform in the browser, Enter the email address in the username/email field.&lt;/li&gt;
&lt;li&gt;Click on &amp;quot;Login&amp;quot;.&lt;/li&gt;
&lt;li&gt;A Google tab will open, displaying the email addresses you are signed in with. Select the email address you entered into the username/email field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Note: Admin users will still be able to log in with their original FlowFuse username/password - this ensures they don&#39;t get locked out of the platform if there is a problem with the SSO configuration&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we&#39;ve covered setting up SSO SAML for your self-hosted FlowFuse platform, exploring how SSO and SAML enhance user experience, improve security, and simplify management. You&#39;ve learned to create an SSO configuration in FlowFuse, set up a SAML app in Google Workspace, and enable seamless authentication.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/</id>
        <title>Building on FlowFuse: Remote Device Monitoring</title>
        <summary>In this article we take a look at how elements of the FlowFuse ecosystem can be used to build powerful IoT applications for monitoring remote devices.</summary>
        <updated>2024-07-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse has established a rich ecosystem of products to help you build bespoke, powerful, low-code applications.&lt;/p&gt;
&lt;p&gt;We&#39;ve seen customers utilizing these to &lt;a href=&quot;https://flowfuse.com/customer-stories/leveraging-node-red-and-flowfuse-to-automate-precision-manufacturing/&quot;&gt;revolutionise precision manufacturing&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/customer-stories/node-red-building-management/&quot;&gt;automate building management&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/customer-stories/un-wmo-nr-data-sharing/&quot;&gt;modernize the distribution of global weather data&lt;/a&gt;, just to name a few examples.&lt;/p&gt;
&lt;p&gt;In this series of articles, we&#39;ll be taking a look at the common architectures and design patterns we are seeing used across our customer base, and how you can use these to build your own applications. To kick things off, this article will focus on &lt;strong&gt;&amp;quot;Remote Device Monitoring&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-case&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#use-case&quot;&gt;Use Case&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You have hundreds, if not, thousands of devices deployed remotely. These could be anything from sensors, to actuators, to entire machines. You need to monitor these devices, and potentially control them. It&#39;s important to know when they are online, that they&#39;re running optimally and if something is about to, or already has, gone wrong.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Diagram showing the breakdown of each component that makes up a &amp;quot;Device Monitoring&amp;quot; use case.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-monitoring-use-case.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Diagram showing the breakdown of each component that makes up a &amp;quot;Device Monitoring&amp;quot; use case.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Breaking it down we have the following fundamental requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Read:&lt;/strong&gt; Reading data from the devices using the relevant protocol&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parse:&lt;/strong&gt; Process the data into a computational format&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compute/Monitor:&lt;/strong&gt; Analysis &amp;amp; monitoring of the data from all devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; Taking action based on the data from the devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we have to consider that this functionality needs to be deployed out to thousands of devices. So, our final requirement is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintain:&lt;/strong&gt; If we update functionality on one device, we may need to be able to easily roll those updates out to other devices. We need to sure it&#39;s easy to update and deploy to our devices, and if anything goes wrong, we should be able to easily find out what the problem is, and get easy access to fix it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#architecture&quot;&gt;Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s consider an example architecture set in an automotive plant:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Diagram showing the architecture of a &amp;quot;Device Monitoring&amp;quot; use case in an automotive plant.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-monitoring-architecture.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Diagram showing an example architecture of a &amp;quot;Device Monitoring&amp;quot; use case in an automotive plant.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Laser Welding Machine:&lt;/strong&gt; Here we have a small system built around a single piece of laser welding hardware. The hardware is connected to a PLC via local network, and the PLC is connected to a local server. Each component here can have Node-RED installed, managed by FlowFuse and accessible via the Device Agent. Node-RED would enable extraction of data from the hardware, and provide a local, bespoke, Dashboard on a nearby PC for monitoring the hardware.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Body Shop:&lt;/strong&gt; Here we have several piece of machinery, each with the &amp;quot;FlowFuse Device Agent&amp;quot; installed. This allows us to manage the Node-RED deployments on these machines remotely from FlowFuse, and easily extract data from the machines for analysis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plant:&lt;/strong&gt; We have multiple servers running at the Planet-level, generally one for each &amp;quot;Shop&amp;quot;, each with their own Device Agent installed, again for easy remote management and deployment of Node-RED, e.g. Dashboards that provide a single HMI for monitoring hardware across a full shop. Here, we also have our instance of FlowFuse. This is the central point for managing all of our Node-RED deployments across the factory floor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Company IT Dept:&lt;/strong&gt; The general IT department of the company would provide multiple servers and services, accessible to a range of departments and the plant. Node-RED could act as a bridge between the Plant and the Company IT Dept, allowing us to easily extract data from the Plant and send it to the Company IT Dept, and vice-versa.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud:&lt;/strong&gt; Here we demonstrate how a company may have external Cloud-based services they&#39;re dependent upon. For example, image analytics services. Node-RED can be used to parse machine imagery, and integrate straight with these external services from the FlowFuse server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This diagram also demonstrates a sample of the rich ecosystem of communication protocols that Node-RED can support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TCP:&lt;/strong&gt; Read and process data from from bespoke and custom devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EtherNet/IP:&lt;/strong&gt; Collect data from Allen Bradley and other EtherNet/IP devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQTT:&lt;/strong&gt;  Modern devices and factory generated IIoT data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPC-UA:&lt;/strong&gt;  Communicate with newer PLCs and OPC Servers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modbus:&lt;/strong&gt;  Data collection from existing Modbus enabled devices like Temperature Probes, Invertors, Encoders&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MC Protocol:&lt;/strong&gt;  Gather data from Mitsubishi PLCs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FINS:&lt;/strong&gt;  Gather data from OMRON PLCs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Siemens S7:&lt;/strong&gt;   Gather data from Siemens PLCs using the S7 Protocol&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;flowfuse-technology-stack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#flowfuse-technology-stack&quot;&gt;FlowFuse Technology Stack&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Given the above architecture, let&#39;s take a look at the relevant FlowFuse offerings and see what they&#39;re contributing:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Lineup of each of the FlowFuse offerings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-ecosystem-lineup.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node-RED:&lt;/strong&gt; Low-code, drag-and-drop integration platform. Here we&#39;d be using it in multiple places to read and parse data from the hardware, define the application logic, conduct analysis and provide alerting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Dashboard:&lt;/strong&gt; An add-on to Node-RED for building interactive user interfaces and dashboards. We use this here to provide visual feedback on local Dashboards for some devices, as well as at the Planet-level to provide an at-a-glance view of our plant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse:&lt;/strong&gt; Centralized platform that provides a single entry point to manage all of your Node-RED applications and deployments, from your device inetrgators, through to your dashboards. FlowFuse provides role-based access control out of the box, so we can easily control who has access to flows, Dashboards and other configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Device Agent:&lt;/strong&gt; Installed onto the relevant servers and hardware, this links you directly, and securely to FlowFuse. Here, we&#39;re deploying it to multiple pieces of machinery, as well as local servers, such that we can easily manage (deploy, upgrade, debug) all of those Node-RED deployments remotely from FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Project Nodes:&lt;/strong&gt; A small collection of nodes for Node-RED, running on FlowFuse, that provide communication over a secure (MQTT-based) connection between devices (our Node-RED deployments on our hardware in this case) and our hosted instances of Node-RED on FlowFuse. Extremely useful for reporting live sensor data back to FlowFuse for analysis, and for reporting information back to our devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#what-next%3F&quot;&gt;What Next?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;deploy-to-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#deploy-to-flowfuse&quot;&gt;Deploy to FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re interested in discussing how your company could benefit from this design pattern, please do &lt;a href=&quot;https://flowfuse.com/contact-us/?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta%20contact%20us&amp;amp;utm_term=high_intent&amp;amp;utm_content=Building%20on%20FlowFuse%3A%20Remote%20Device%20Monitoring/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;customer-stories&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/building-on-flowfuse-devices/#customer-stories&quot;&gt;Customer Stories&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to deep dive further into how this design pattern has been used by our customers, we have some customer stories that you might find interesting:&lt;/p&gt;
&lt;ul class=&quot;grid grid-cols-1 sm:grid-cols-2 gap-4 px-0 list-none&quot;&gt;
&lt;li class=&quot;customer-story-tile w-full my-2 border px-0 rounded-lg hover:drop-shadow-lg hover:border-blue-600 transition ease-in-out duration-300 bg-white&quot;&gt;
    &lt;a href=&quot;https://flowfuse.com/customer-stories/leveraging-node-red-and-flowfuse-to-automate-precision-manufacturing&quot; class=&quot;w-full flex flex-col group hover:no-underline h-full m-0&quot;&gt;
        &lt;div class=&quot;&quot;&gt;
            &lt;div&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;relative border-b&quot;&gt;
&lt;div class=&quot;w-full h-52 sm:h-48 ff-image-cover ff-image-top-rounded&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
&lt;img src=&quot;https://flowfuse.com/images/stories/abrasive_tech.jpg&quot; alt=&quot;Image representing Revolutionizing Precision Manufacturing with Node-RED&quot; /&gt;
&lt;/picture&gt;
&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;flex flex-col mt-1 mb-0 p-5 pt-3 gap-2&quot;&gt;
&lt;label class=&quot;font-bold&quot;&gt;&lt;span class=&quot;text-gray-400&quot;&gt;Abrasive Technology&lt;/span&gt;&lt;/label&gt;
&lt;h3 class=&quot;group-hover:text-blue-600 font-medium m-0 mt-0 mb-2&quot; style=&quot;line-height: 1.6rem&quot;&gt;&lt;span class=&quot;text-lg&quot;&gt;Revolutionizing Precision Manufacturing with Node-RED&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;customer-story-tile w-full my-2 border px-0 rounded-lg hover:drop-shadow-lg hover:border-blue-600 transition ease-in-out duration-300 bg-white&quot;&gt;
    &lt;a href=&quot;https://flowfuse.com/customer-stories/leveraging-node-red-and-flowfuse-to-revolutionize-irrigation&quot; class=&quot;w-full flex flex-col group hover:no-underline h-full m-0&quot;&gt;
        &lt;div class=&quot;&quot;&gt;
            &lt;div&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;relative border-b&quot;&gt;
&lt;div class=&quot;w-full h-52 sm:h-48 ff-image-cover ff-image-top-rounded&quot;&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
&lt;img src=&quot;https://flowfuse.com/images/stories/pidd-view.png&quot; alt=&quot;Image representing Leveraging Node-RED and FlowFuse to Revolutionize Irrigation&quot; /&gt;
&lt;/picture&gt;
&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;flex flex-col mt-1 mb-0 p-5 pt-3 gap-2&quot;&gt;
&lt;label class=&quot;font-bold&quot;&gt;&lt;span class=&quot;text-gray-400&quot;&gt;Paloma Irrigation and Drainage District&lt;/span&gt;&lt;/label&gt;
&lt;h3 class=&quot;group-hover:text-blue-600 font-medium m-0 mt-0 mb-2&quot; style=&quot;line-height: 1.6rem&quot;&gt;&lt;span class=&quot;text-lg&quot;&gt;Leveraging Node-RED and FlowFuse to Revolutionize Irrigation&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/</id>
        <title>Deploying FlowFuse with Docker on an Ubuntu server</title>
        <summary>Step-by-step guide on how to deploy FlowFuse with Docker on Ubuntu server</summary>
        <updated>2024-07-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;With Node-RED&#39;s increasing role in IoT, FlowFuse Cloud has become a favored platform for deploying production Node-RED applications. It offers &lt;a href=&quot;https://flowfuse.com/platform/features/&quot;&gt;extensive features&lt;/a&gt; at a low cost, reducing operational overhead. However, the cloud is not the only option we provide; we also offer a self-hosted option for users who prefer to deploy FlowFuse on their servers. This guide demonstrates how to deploy FlowFuse on your Ubuntu server using Docker, covering key aspects such as domain setup, email, SSL, and more for real-world production scenarios&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: While the approach provided in this article is an older method for deploying FlowFuse and still works, I recommend following the newer, simpler, and quicker approach. For more details, refer to the official &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-docker%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#what-is-docker%3F&quot;&gt;What is Docker?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/guides/docker-concepts/the-basics/what-is-an-image/&quot;&gt;Docker&lt;/a&gt; is an open-source platform that simplifies how applications are deployed, scaled, and managed through containerization. It enables you to package all components required by your project such as code, libraries, and dependencies into a single, portable unit known as a &lt;a href=&quot;https://docs.docker.com/guides/docker-concepts/the-basics/what-is-a-container/&quot;&gt;Docker container&lt;/a&gt;. These containers ensure consistency in application environments and ease deployment by ensuring that applications run predictably across different computing environments, whether on a developer&#39;s laptop, a server, or a cloud platform.&lt;/p&gt;
&lt;h2 id=&quot;deploying-flowfuse-on-ubuntu-server-with-docker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#deploying-flowfuse-on-ubuntu-server-with-docker&quot;&gt;Deploying FlowFuse on Ubuntu server with Docker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before proceeding, ensure you have your domain and a server with Ubuntu installed, and Docker is installed on it. For more information, refer to &lt;a href=&quot;https://docs.docker.com/compose/install/&quot;&gt;Docker Compose Installation&lt;/a&gt;. Furthermore, If your server has Ubuntu installed without a GUI, you can connect to it from your computer using &lt;a href=&quot;https://itsfoss.com/set-up-ssh-ubuntu/&quot;&gt;SSH&lt;/a&gt;, allowing you to run commands from your local computer on the server.&lt;/p&gt;
&lt;h3 id=&quot;adding-dns-records-for-your-domain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#adding-dns-records-for-your-domain&quot;&gt;Adding DNS records for your domain&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make your application accessible on the internet via your domain name, adding DNS records is crucial. These records serve as a vital link between your domain name (like example.com) and your server&#39;s IP address. They ensure that when users type your domain into their browsers, they&#39;re directed to the correct location where your application is hosted.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of panel to add dns records provided by my domain provider&quot; alt=&quot;&amp;quot;Screenshot of panel to add dns records provided by my domain provider&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/domain-provider-panel.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Log in to your Domain Provider&#39;s Panel and access the DNS settings of the domain you want to use for the FlowFuse platform.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add entry first entry type: &amp;quot;A&amp;quot;, enter &amp;quot;@&amp;quot; into the name field (it points to the domain name itself), and the public IP of your Ubuntu server into the data field.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add entry second entry type: &amp;quot;A&amp;quot;, enter &amp;quot;*&amp;quot; into the name field (adding * serves as the &lt;a href=&quot;https://docs.digitalocean.com/glossary/wildcard-record/&quot;&gt;wildcard domain entry&lt;/a&gt; to the IP address of the host running Docker, we are doing this because the FlowFuse application will be hosted on the &lt;code&gt;forge.your-domain-name.com&lt;/code&gt; and when creating instances for each, our FlowFuse application will use unique subdomain ) and public IP of your Ubuntu server into the data field.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the last entry type: &amp;quot;A&amp;quot;, and enter &amp;quot;www&amp;quot; into the name field (we are adding this because previously domain names used to have the www prefix) and the public IP of your Ubuntu server into the data field.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;installing-and-configuring-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#installing-and-configuring-flowfuse&quot;&gt;Installing and configuring FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse uses Docker Compose to install and manage the required components. We have built and maintaining that Docker Compose project.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the latest release &lt;code&gt;tar.gz&lt;/code&gt; from our &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/releases/latest&quot;&gt;Docker Compose project&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-62&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-62&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /opt&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-62&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-63&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-63&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;link of the latest tar.gz release&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-63&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Unpack this release with the following command. Make sure to replace the release name with the actual release name that you downloaded:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-71&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-71&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-xvzf&lt;/span&gt; vx.x.x.tar.gz&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-71&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Enter the folder with the following command. Again, don&#39;t forget to replace the release name with the actual release name that you downloaded:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-79&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-79&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; docker-compose-x.x.x&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-79&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Now, update the FlowFuse configuration file &lt;code&gt;flowforge.yml&lt;/code&gt; with your domain name. Currently, it is configured with &lt;code&gt;example.com&lt;/code&gt;. To update it quickly, use the following command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-87&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-87&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/example.com/&amp;lt;replace-with-your-domain-name&gt;/g&#39;&lt;/span&gt; ./etc/flowforge.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-87&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Next, update the Docker Compose configuration file &lt;code&gt;docker-compose.yml&lt;/code&gt; with your domain:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-95&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-95&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;s/example.com/&amp;lt;replace-with-your-domain-name&gt;/g&#39;&lt;/span&gt; ./docker-compose.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-95&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot the terminal showing the updates made in docker-compose.yml file&quot; alt=&quot;&amp;quot;Screenshot the terminal showing the updates made in docker-compose.yml file&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/docker-compose-update.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot the terminal showing the updates made in &#39;docker-compose.yml&#39; file&quot; alt=&quot;&amp;quot;Screenshot the terminal showing the updates made in &#39;docker-compose.yml&#39; file&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/docker-compose-update-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;flowforge.yml&lt;/code&gt; file was updated to include our domain in key fields: &lt;code&gt;domain&lt;/code&gt;, &lt;code&gt;base_url&lt;/code&gt;, and &lt;code&gt;broker.public_url&lt;/code&gt;. These adjustments ensure that instance names on Docker platforms incorporate your domain, provide accurate URLs for accessing the platform, and specify the correct URL for devices to connect to the broker if different from &lt;code&gt;broker.url&lt;/code&gt;. Additionally, in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, we configured &lt;code&gt;VIRTUAL_HOST&lt;/code&gt; and &lt;code&gt;LETSENCRYPT_HOST&lt;/code&gt; to reflect our domain.&lt;/p&gt;
&lt;p&gt;For more details on these configuration changes, refer to the &lt;a href=&quot;https://flowfuse.com/docs/install/configuration/#configuring-flowfuse&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;securing-communication-with-ssl&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#securing-communication-with-ssl&quot;&gt;Securing Communication with SSL&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Securing communication with &lt;a href=&quot;https://www.youtube.com/watch?v=SJJmoDZ3il8&quot;&gt;SSL (Secure Sockets Layer)&lt;/a&gt; is crucial for protecting data transmitted between your users and the server. Adding SSL requires obtaining a certificate from a trusted certificate authority (CA) and configuring your server to use this certificate. Configuring SSL manually can be a headache, so we have provided a setup you need to enable.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Docker Compose file in your editor:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-121&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-121&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; docker-compose.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-121&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Uncomment the following lines by removing the &lt;code&gt;#&lt;/code&gt; symbol:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-129&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-129&quot; class=&quot;language-yaml&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;# - &quot;./certs:/etc/nginx/certs&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-129&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-130&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-130&quot; class=&quot;language-yaml&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;# - &quot;443:443&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# environment:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;# - &quot;HTTPS_METHOD=redirect&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-130&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-131&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-131&quot; class=&quot;language-yaml&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;# acme:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   image: nginxproxy/acme-companion&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   restart: always&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   volumes:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#     - &quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#     - &quot;./acme:/etc/acme.sh&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   volumes_from:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#     - nginx:rw&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   environment:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#     - &quot;DEFAULT_EMAIL=mail@example.com&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#   depends_on:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#     - &quot;nginx&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-131&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Update the lines with your domain and email associated with the domain, then save the file:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-139&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-139&quot; class=&quot;language-yaml&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DEFAULT_EMAIL=your-email@example.com&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LETSENCRYPT_HOST=mqtt.yourdomain.com&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LETSENCRYPT_HOST=forge.yourdomain.com&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-139&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot the terminal showing the update made in `docker-compose.yml` file for ssl configuration&quot; alt=&quot;&amp;quot;Screenshot the terminal showing the update made in `docker-compose.yml` file for ssl configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/docker-compose-yml-acme-update.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Open the &lt;code&gt;flowforge.yml&lt;/code&gt; file in your editor:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-150&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-150&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/flowforge.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-150&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Update the &lt;code&gt;base_url&lt;/code&gt; to start with &lt;code&gt;https://&lt;/code&gt; instead of &lt;code&gt;http://&lt;/code&gt; and the &lt;code&gt;broker.public_url&lt;/code&gt; entry to start with &lt;code&gt;wss://&lt;/code&gt; instead of &lt;code&gt;ws://&lt;/code&gt;, then save the file.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-158&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-158&quot; class=&quot;language-yaml&quot;&gt;    base_url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//yourdomain.com&lt;br /&gt;&lt;br /&gt;    broker&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      public_url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//mqtt.yourdomain.com&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-158&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the terminal showing the update made in &#39;broker&#39;s public_url&#39; in the `flowforge.yml` file for SSL configuration&quot; alt=&quot;&amp;quot;Screenshot of the terminal showing the update made in &#39;broker&#39;s public_url&#39; in the `flowforge.yml` file for SSL configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowforge-yml-https-update.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the terminal showing the update made in &#39;base_url&#39; in the `flowforge.yml` file for SSL configuration&quot; alt=&quot;&amp;quot;Screenshot of the terminal showing the update made in &#39;base_url&#39; in the `flowforge.yml` file for SSL configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowforge-yml-https-update2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now, when we start our application the acme container will also start and will generate the certificates with let&#39;s encrypt on demand for the forge app and then for each of the instances as they are started.&lt;/p&gt;
&lt;h3 id=&quot;configuring-flowfuse-to-enable-and-use-the-email-feature&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#configuring-flowfuse-to-enable-and-use-the-email-feature&quot;&gt;Configuring FlowFuse to Enable and Use the Email Feature&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse platform allows you to send invitations to other users within the platform and via email. It also supports receiving critical alerts and resetting passwords through email. To use these features, you need to enable and configure email in FlowFuse with your email address. Before you begin, make sure you have an email ID with an app password. FlowFuse supports Gmail and Outlook emails.&lt;/p&gt;
&lt;h4 id=&quot;creating-an-app-password-for-your-email&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#creating-an-app-password-for-your-email&quot;&gt;Creating an App Password for Your Email&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you&#39;re unfamiliar with generating an app password, watch these helpful videos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hXiPshHn9Pw&quot;&gt;Creating a Gmail app password&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5ukSRLRDQIw&quot;&gt;Creating an Outlook app password&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;enabling-and-configuring-email-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#enabling-and-configuring-email-in-flowfuse&quot;&gt;Enabling and Configuring Email in FlowFuse&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;code&gt;flowforge.yml&lt;/code&gt; config file in your editor:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-202&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-202&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; /etc/flowforge.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-202&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Update the email configuration section with your email details:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;For Gmail:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-213&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-213&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  enabled&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;br /&gt;  debug&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;br /&gt;  smtp&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    host&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; smtp.gmail.com&lt;br /&gt;    port&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;465&lt;/span&gt;&lt;br /&gt;    secure&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;br /&gt;    auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      user&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; your&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;email@gmail.com&lt;br /&gt;      pass&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; your&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;password&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-213&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;For Outlook:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-217&quot;&gt;
  &lt;pre class=&quot;language-yml&quot;&gt;&lt;code id=&quot;code-217&quot; class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  enabled&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;br /&gt;  debug&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;br /&gt;  smtp&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    host&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; smtp.office365.com&lt;br /&gt;    port&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;587&lt;/span&gt;&lt;br /&gt;    secure&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;br /&gt;    tls&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      ciphers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SSLv3&quot;&lt;/span&gt;&lt;br /&gt;      rejectUnauthorized&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;br /&gt;    auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      user&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; your&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;email@outlook.com&lt;br /&gt;      pass&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; your&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;password&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-217&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;running-flowfuse-application&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#running-flowfuse-application&quot;&gt;Running FlowFuse Application&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have completed the basic production-level configuration for running the FlowFuse application. Before running it, we need to ensure that we have the &lt;code&gt;flowfuse/node-red&lt;/code&gt; container downloaded, which will be used as the default Node-RED stack.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To download the Node-RED container, run the following command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-231&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-231&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; pull flowfuse/node-red&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-231&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Now, to run the FlowFuse application, execute the following command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-239&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-239&quot; class=&quot;language-bash&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; compose &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; flowforge up &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-239&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you see an output similar to the following image, it indicates that all containers that are required for the flowfuse application to run correctly are running.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the terminal showing the all containers are running successfully that are required for the flowfuse to run&quot; alt=&quot;&amp;quot;Screenshot of the terminal showing the all containers are running successfully that are required for the flowfuse to run&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowforge-yml-successfully-running-container.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can now access your self-hosted FlowFuse platform on the internet using the URL &lt;code&gt;forge.&amp;lt;yourdomain&amp;gt;.com&lt;/code&gt;, and if your website shows the &lt;code&gt;https&lt;/code&gt; as following that means the SSL configurations are also correct.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the browser window with flowfuse platform opened&quot; alt=&quot;&amp;quot;Screenshot of the browser window with flowfuse platform opened&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/deploying-flowfuse-successfull-with-ssl.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;setting-up-the-flowfuse-platform&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#setting-up-the-flowfuse-platform&quot;&gt;Setting up the FlowFuse Platform&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you open the platform in your browser for the first time, you&#39;ll need to create an administrator account and perform initial configurations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the platform in your browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &amp;quot;START SETUP&amp;quot; button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter the username, full name, email, and password, and confirm the password to the administrator user account. This first user will have full access to the platform, allowing them to configure settings, and manage users and teams.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, If you intend to use the FlowFuse Enterprise Edition, enter your license details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alternatively, you can continue with the FlowFuse Community Edition (CE), which is free, by clicking &amp;quot;Continue with FlowFuse CE&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;additional-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/deploying-flowfuse-with-docker/#additional-resources&quot;&gt;Additional resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Deploying FlowFuse with Docker Documentation&lt;/a&gt;: This documentation covers everything in detail on how to install FlowFuse using Docker.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=qQwAPuz9bEk&quot;&gt;Deploying FlowFuse with Docker on Ubuntu youtube video&lt;/a&gt;: This YouTube video demonstrates how to deploy FlowFuse using Docker on an Ubuntu server for your server&#39;s local network.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/install/introduction/#do-you-need-help%3F-installation-service&quot;&gt;Form for requesting Installation Service&lt;/a&gt;: Fill this form if you need assistance with the installation process.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/</id>
        <title>Calling a Python script from Node-RED</title>
        <summary>Guide on how to execute Python scripts from Node-RED</summary>
        <updated>2024-07-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Python&#39;s robust data processing capabilities and extensive libraries are well-known in programming. When combined with Node-RED, these technologies can synergize to elevate data analytics and automation. This guide walks you through integrating Python scripts with Node-RED. You&#39;ll gain practical insights, troubleshooting tips, and effective techniques for executing scripts, enabling you to leverage this powerful combination for your IoT projects.&lt;/p&gt;
&lt;h2 id=&quot;why-use-python-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#why-use-python-with-node-red&quot;&gt;Why use python with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating Python and Node-RED can significantly enhance your IoT and automation initiatives by leveraging their distinct strengths. Node-RED excels in creating easy workflows, efficiently processing data streams, and integrating hardware, APIs, and. Meanwhile, Python offers a rich set of libraries for advanced tasks such as machine learning and AI, pivotal in realizing Industry 4.0 concepts.&lt;/p&gt;
&lt;p&gt;This combination allows developers to build robust and flexible solutions. For instance, while Node-RED manages data flow and device communication, Python can perform complex analytics, and predictive modeling, or integrate with AI frameworks. This integration bridges the gap between data collection and actionable insights, enabling systems to make informed decisions autonomously.&lt;/p&gt;
&lt;h2 id=&quot;installing-python&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#installing-python&quot;&gt;Installing Python&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When executing Python scripts, it&#39;s essential to have the Python runtime installed on your system. Before proceeding, make sure you have it installed. You can follow the &lt;a href=&quot;https://wiki.python.org/moin/BeginnersGuide/Download&quot;&gt;official guide&lt;/a&gt; for instructions.&lt;/p&gt;
&lt;p&gt;To verify if Python is installed, open your terminal and execute:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-21&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-21&quot; class=&quot;language-bash&quot;&gt;python &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-21&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of terminal showing the python version installed, conforming it is installed&quot; alt=&quot;&amp;quot;Screenshot of terminal showing the python version installed, conforming it is installed&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/calling-python-script-from-node-red-py-conformation.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The above command displays the version of Python installed on your system as shown in the above image. If the above command doesn&#39;t work, try:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-28&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-28&quot; class=&quot;language-bash&quot;&gt;python3 &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-28&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The specific command to use depends on how Python was installed and configured on your system. However, make sure to use &lt;code&gt;python &amp;lt;filename&amp;gt;.py&lt;/code&gt; if the first command works, or &lt;code&gt;python3 &amp;lt;filename&amp;gt;.py&lt;/code&gt; if the second command works, while executing Python scripts.&lt;/p&gt;
&lt;h2 id=&quot;executing-python-script-from-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#executing-python-script-from-node-red&quot;&gt;Executing Python Script from Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s now see how to call a Python script from Node-RED. First, we&#39;ll create a basic script file that contains a function to print text in the console based on input. Currently, the function uses hardcoded input. To create this file using Node-RED, import the following flow, deploy it, and press the inject button:&lt;/p&gt;
&lt;div id=&quot;nr-flow-186&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow186 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;b9d7d6aff0016631&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2e1daccf2a7b3d0f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d2d1450deaa588f4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;.&#92;&#92;&#92;&#92;example.py&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e140a8508fb10d96&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e140a8508fb10d96&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2e1daccf2a7b3d0f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;def main():&#92;&#92;n    # Hardcoded value&#92;&#92;n    user_input = 20  &#92;&#92;n    &#92;&#92;n    # Check if the input is numeric&#92;&#92;n    if isinstance(user_input, int) or (isinstance(user_input, str) and user_input.isdigit()):&#92;&#92;n        number = int(user_input) if isinstance(user_input, str) else user_input&#92;&#92;n        &#92;&#92;n        # Conditionally render based on the input value&#92;&#92;n        if number &amp;lt; 0:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Negative number entered&#92;&#92;&#92;&quot;)&#92;&#92;n        elif number == 0:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Zero entered&#92;&#92;&#92;&quot;)&#92;&#92;n        else:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Positive number entered&#92;&#92;&#92;&quot;)&#92;&#92;n    else:&#92;&#92;n        print(&#92;&#92;&#92;&quot;Invalid input. Please enter a valid number.&#92;&#92;&#92;&quot;)&#92;&#92;n&#92;&#92;nif __name__ == &#92;&#92;&#92;&quot;__main__&#92;&#92;&#92;&quot;:&#92;&#92;n    main()&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d2d1450deaa588f4&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow186.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-186&#39;) })&lt;/script&gt;
&lt;p&gt;Now, let&#39;s execute this Python script from Node-RED. To do that, we will use Node-RED&#39;s &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/exec/&quot;&gt;Exec&lt;/a&gt; node, which allows running commands on your system.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag an Exec node onto the canvas and Configure the command to &lt;code&gt;python ./example.py -u&lt;/code&gt;. The -u flag prevents potential output buffering issues when executing Python scripts via exec.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Exec node executing python file&quot; alt=&quot;&amp;quot;Screenshot of the Exec node executing python file&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/calling-python-scrpt-from-node-red-exec-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag a Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the Exec node, and the output of the Exec node to the input of Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&quot;nr-flow-187&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow187 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2e26b84c0ce17312&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;exec&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;command&#92;&quot;:&#92;&quot;python ./example.py -u&#92;&quot;,&#92;&quot;addpay&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;append&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useSpawn&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;timer&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;winHide&#92;&quot;:false,&#92;&quot;oldrc&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;89589c56117004e0&#92;&quot;],[&#92;&quot;7fdb901b144749c2&#92;&quot;],[&#92;&quot;3f49b49308941782&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;739e08c1ec77c2a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2e26b84c0ce17312&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;89589c56117004e0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Output&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7fdb901b144749c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Error&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3f49b49308941782&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Return code&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:710,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow187.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-187&#39;) })&lt;/script&gt;
&lt;p&gt;Now, when you deploy this flow and click on the inject node to execute the file, you should see the text &#39;Positive number entered&#39; and &lt;code&gt;{ code: 0 }&lt;/code&gt;, which indicates your script has been successfully executed.&lt;/p&gt;
&lt;h2 id=&quot;reading-temperature-sensor-using-python-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#reading-temperature-sensor-using-python-script&quot;&gt;Reading Temperature Sensor using Python script&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Having explored how to run a Python script within Node-RED with the basic practical example, let&#39;s move to a real-world scenario. We&#39;ll demonstrate how to read sensor data using Python, despite Node-RED providing numerous community-built nodes for this purpose. This approach provides deeper insights into integrating external scripts, showcasing the flexibility of Node-RED for custom solutions.&lt;/p&gt;
&lt;p&gt;Before proceeding, ensure that Node-RED is running on a device connected to a temperature sensor. For detailed instructions, refer to &lt;a href=&quot;https://flowfuse.com/node-red/hardware/&quot;&gt;Setting Up Node-RED on Different Hardware&lt;/a&gt;, In this case, we are running Node-RED on a Raspberry Pi 5 with a DHT11 sensor connected to it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto the canvas, and set repeat to 1 seconds of interval.&lt;/li&gt;
&lt;li&gt;Drag an Exec node and set the path to &lt;code&gt;python &amp;lt;filename&amp;gt;.py&lt;/code&gt;, replace the filename with the name of the file which reads the sensor data, and make sure the python file doesn&#39;t contain the loop.&lt;/li&gt;
&lt;li&gt;Drag the JSON node onto the canvas and set the action to &amp;quot;Always convert to JSON object&amp;quot;.&lt;/li&gt;
&lt;li&gt;Drag the Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the Exec node and output of the Exec node to the input of the JSON node, and finally the JSON node&#39;s output to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below is the complete flow which creates the Python file to read the DHT11 sensor and executes that file after 1 second of interval. After deploying the flow you should able to see the sensor data on the debug sidebar as shown in the below image.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the Node-RED flow executing the python script that reads the sensor data&quot; alt=&quot;&amp;quot;Image showing the Node-RED flow executing the python script that reads the sensor data&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/calling-python-scrpt-from-node-red-output.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Note: The Python script uses the &lt;a href=&quot;https://docs.circuitpython.org/projects/dht/en/latest/index.html&quot;&gt;adafruit-circuitpython&lt;/a&gt; to read the sensor data so make sure to install it. Additionally, the code contained in the template node in the following flow considers that your sensor&#39;s signal pin is connected to GPIO 4.&lt;/p&gt;
&lt;div id=&quot;nr-flow-188&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow188 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;94bc6fa766c4b397&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;~/sensor.py&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:false,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9b08eee57f666de5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;37453becdf842bd7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;import time&#92;&#92;nimport board&#92;&#92;nimport adafruit_dht&#92;&#92;nimport json&#92;&#92;n&#92;&#92;ndef publish():&#92;&#92;n    dhtDevice = adafruit_dht.DHT11(board.D4)&#92;&#92;n    try:&#92;&#92;n        temperature_c = dhtDevice.temperature&#92;&#92;n        humidity = dhtDevice.humidity&#92;&#92;n&#92;&#92;n        # Create JSON object&#92;&#92;n        data = {&#92;&#92;n            &#92;&#92;&#92;&quot;temperature_c&#92;&#92;&#92;&quot;: temperature_c,&#92;&#92;n            &#92;&#92;&#92;&quot;humidity&#92;&#92;&#92;&quot;: humidity&#92;&#92;n        }&#92;&#92;n&#92;&#92;n        # Convert JSON object to string and print&#92;&#92;n        print(json.dumps(data))&#92;&#92;n&#92;&#92;n    except RuntimeError as error:&#92;&#92;n        print(error.args[0])&#92;&#92;n    except Exception as error:&#92;&#92;n        dhtDevice.exit()&#92;&#92;n        raise error&#92;&#92;n    finally:&#92;&#92;n        dhtDevice.exit()&#92;&#92;n&#92;&#92;ndef run():&#92;&#92;n    publish()&#92;&#92;n&#92;&#92;nif __name__ == &#39;__main__&#39;:&#92;&#92;n    run()&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;94bc6fa766c4b397&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5b3642d39c122576&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;88144cbc887aada9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c896267214914641&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1b1d792011ffac2c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;kill&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;g&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;37453becdf842bd7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c896267214914641&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;exec&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;command&#92;&quot;:&#92;&quot;python ~/sensor.py -u&#92;&quot;,&#92;&quot;addpay&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;append&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useSpawn&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;timer&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;winHide&#92;&quot;:false,&#92;&quot;oldrc&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:400,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1d02a33a018f0f8d&#92;&quot;],[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1d02a33a018f0f8d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pretty&#92;&quot;:false,&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5b3642d39c122576&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9b08eee57f666de5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;343a9f704951f3ed&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create python file that reads the sensor data&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;216eb1333b2c264c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Execute the python file that read the data&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow188.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-188&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;executing-python-script-with-arguments-from-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#executing-python-script-with-arguments-from-node-red&quot;&gt;Executing Python Script with Arguments from Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, let&#39;s revisit our first example. In that example, we executed a simple Python file with a hardcoded value. Now, we&#39;ll learn how to pass arguments or inputs to the Python script when executing from Node-RED. For this, we&#39;ll need to update the file. Import the following flow, deploy it, and click on the inject button to create the file.&lt;/p&gt;
&lt;div id=&quot;nr-flow-189&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow189 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;b9d7d6aff0016631&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2e1daccf2a7b3d0f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d2d1450deaa588f4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;./example.py&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e140a8508fb10d96&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e140a8508fb10d96&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2e1daccf2a7b3d0f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;import sys&#92;&#92;n&#92;&#92;ndef main():&#92;&#92;n    if len(sys.argv) != 2:&#92;&#92;n        print(&#92;&#92;&#92;&quot;Usage: python your_script.py &amp;lt;number&amp;gt;&#92;&#92;&#92;&quot;)&#92;&#92;n        return&#92;&#92;n    &#92;&#92;n    user_input = sys.argv[1]&#92;&#92;n    &#92;&#92;n    # Check if the input is numeric&#92;&#92;n    if user_input.isdigit() or (user_input[0] == &#39;-&#39; and user_input[1:].isdigit()):&#92;&#92;n        number = int(user_input)&#92;&#92;n        &#92;&#92;n        # Conditionally render based on the input value&#92;&#92;n        if number &amp;lt; 0:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Negative number entered&#92;&#92;&#92;&quot;)&#92;&#92;n        elif number == 0:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Zero entered&#92;&#92;&#92;&quot;)&#92;&#92;n        else:&#92;&#92;n            print(&#92;&#92;&#92;&quot;Positive number entered&#92;&#92;&#92;&quot;)&#92;&#92;n    else:&#92;&#92;n        print(&#92;&#92;&#92;&quot;Invalid input. Please enter a valid number.&#92;&#92;&#92;&quot;)&#92;&#92;n&#92;&#92;nif __name__ == &#92;&#92;&#92;&quot;__main__&#92;&#92;&#92;&quot;:&#92;&#92;n    main()&#92;&#92;n&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d2d1450deaa588f4&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow189.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-189&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag the Exec node onto the canvas, set the command to &lt;code&gt;python -u ./example.py &amp;lt;arg&amp;gt;&lt;/code&gt;, and replace the &lt;code&gt;&amp;lt;arg&amp;gt;&lt;/code&gt; with your argument.&lt;/li&gt;
&lt;li&gt;Now Drag the Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the Exec node, and the output of the Exec node to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you examine the Python file we&#39;ve created, you&#39;ll notice the use of the &#39;sys&#39; module, which allows us to read command-line arguments. In our context, we execute the command &lt;code&gt;python ./example.py -30&lt;/code&gt;. By accessing &lt;code&gt;sys.argv[1]&lt;/code&gt;, we retrieve the argument -30. The index 1 is used because &lt;code&gt;sys.argv[0]&lt;/code&gt; provides the filename of the script being executed. Additionally, Python supports passing multiple arguments, so that you can pass as many arguments as you want.&lt;/p&gt;
&lt;div id=&quot;nr-flow-190&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow190 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;2e26b84c0ce17312&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;exec&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;command&#92;&quot;:&#92;&quot;python -u ./example.py  -30&#92;&quot;,&#92;&quot;addpay&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;append&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;useSpawn&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;timer&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;winHide&#92;&quot;:false,&#92;&quot;oldrc&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;89589c56117004e0&#92;&quot;],[&#92;&quot;7fdb901b144749c2&#92;&quot;],[&#92;&quot;3f49b49308941782&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;739e08c1ec77c2a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2e26b84c0ce17312&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;89589c56117004e0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Output&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7fdb901b144749c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Error&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3f49b49308941782&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;FFF0000000000001&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Return code&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:750,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow190.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-190&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/calling-python-script-from-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we&#39;ve demonstrated how to seamlessly execute Python scripts from Node-RED, along with troubleshooting tips and instructions on passing arguments to scripts. By leveraging Python&#39;s extensive libraries for data processing, machine learning, and other tasks in conjunction with Node-RED, developers can build powerful IoT solutions with ease.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/</id>
        <title>FlowFuse 2.6: AI Infused Node-RED, Persistent File Storage &amp; Lots More</title>
        <summary>Lowering the barrier to entry for new users, and enhancing the flexibility and functionality of the platform.</summary>
        <updated>2024-07-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.6 is packed with great new features, and in this release we&#39;ve had a heavy focus on improving the development experience of Node-RED, lowering the barrier to entry for new users and aligning to our &lt;a href=&quot;https://flowfuse.com/handbook/engineering/product/strategy/#simplified-hosting&quot;&gt;Simplified Hosting&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/handbook/engineering/product/strategy/#low-code&quot;&gt;Low-Code&lt;/a&gt; plans from our &lt;a href=&quot;https://flowfuse.com/handbook/engineering/product/strategy/&quot;&gt;Product Strategy&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improving-the-node-red-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#improving-the-node-red-experience&quot;&gt;Improving the Node-RED Experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst a big part of FlowFuse is the ability to run Node-RED, we&#39;re also focussing on how to improve the experience of &lt;em&gt;building&lt;/em&gt; with Node-RED on FlowFuse too.&lt;/p&gt;
&lt;h3 id=&quot;ai-infused-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#ai-infused-node-red&quot;&gt;AI-Infused Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;FlowFuse Expert&amp;quot; dialog box&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/assistant-dialog-function-node-builder.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of an example instruction sent to FlowFuse Expert.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the joys of Node-RED is how it empowers users not experienced with development to create bespoke applications. A popular and very powerful node in Node-RED is the &amp;quot;function&amp;quot; node. This node allows users to write JavaScript code to manipulate messages. However, this can be daunting for users who are not familiar with JavaScript, it&#39;s a steep learning curve. As such, when you run Node-RED in FlowFuse, you&#39;ll be able to use the &lt;strong&gt;Node-RED Assistant&lt;/strong&gt; in both the Editor toolbar, and the function nodes:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;FlowFuse Expert&amp;quot; button available in the Editor Toolbar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/assistant-toolbar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &amp;quot;FlowFuse Expert&amp;quot; button available in the Editor Toolbar&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;Ask the FlowFuse Expert&amp;quot; button available in the function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/assistant-function-node-inline-code-lens.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &amp;quot;Ask the FlowFuse Expert&amp;quot; button available in the function node&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Node-RED Assistant is an AI-powered tool that can help you write JavaScript code in the function node. It can suggest code snippets, help you debug your code, and even write code for you. This is a game-changer for users who are inexperienced with JavaScript, as it lowers the barrier to entry and makes it easier to create applications.&lt;/p&gt;
&lt;h3 id=&quot;immersive-editor-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#immersive-editor-experience&quot;&gt;Immersive Editor Experience&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;During our investigation on how FlowFuse and Node-RED are used together, we found out that many users have to frequently switch between the Node-RED Editor and FlowFuse UI. This back-and-forth movement was often necessary to view logs, save snapshots, restart the Editor after updates, and perform other tasks.&lt;/p&gt;
&lt;p&gt;We&#39;re always seeking to reduce friction in the FlowFuse user experience, and as such, we&#39;ve introduced a large overhaul of the developer experience for Node-RED when running in FlowFuse, in what we&#39;re calling the &amp;quot;Immersive Editor&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;Immersive Editor&amp;quot; view&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/immersive-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &amp;quot;Immersive Editor&amp;quot; view, where the FlowFuse navigation is available as a floating bar.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, the instances tabs are all available in the &lt;em&gt;same&lt;/em&gt; view as the Editor.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;Collapsed&amp;quot; FlowFuse bar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/immersive-editor-collapsed.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &amp;quot;FlowFuse&amp;quot; button at the bottom of the Node-RED Editor.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Don&#39;t worry though, if you want the full editor experience again, you can just collapse the FlowFuse menus down to a little &amp;quot;FlowFuse&amp;quot; button at the bottom.&lt;/p&gt;
&lt;p&gt;The new Immersive Editor is available for instances running Node-RED 4.0.2 or later - older versions of Node-RED will still use the separate views.&lt;/p&gt;
&lt;h2 id=&quot;persistent-file-storage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#persistent-file-storage&quot;&gt;Persistent File Storage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since the early days of FlowFuse, we have provided custom File nodes that can be used to read and write individual files from a flow. This was necessary because the local file system was not considered persistent; restarting an instance would reset the file system back to how it was when the instance first started.&lt;/p&gt;
&lt;p&gt;Whilst this solved the immediate problem for the File nodes, we know there were 3rd party nodes that would want to use the file system as well - and we couldn&#39;t expect them to update to work with our custom solution.&lt;/p&gt;
&lt;p&gt;With the 2.6 release, each instance now gets a piece of persistent file system they can read and write to normally, from any node - with full confidence those files will be persisted between restarts.&lt;/p&gt;
&lt;p&gt;This unlocks lots of new capabilities using nodes from the community. For example, the &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-sqlite&quot;&gt;SQLite&lt;/a&gt; nodes can be used to quickly add a locally managed database to store your data in.&lt;/p&gt;
&lt;p&gt;All newly created instances of FlowFuse Cloud from today will have this storage enabled. If you have an existing instance you&#39;d like to move over, then do get &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;in touch&lt;/a&gt; and we can help move you over.&lt;/p&gt;
&lt;h2 id=&quot;other-highlights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#other-highlights&quot;&gt;Other Highlights&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;compact-applications-view&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#compact-applications-view&quot;&gt;Compact Applications View&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is a great example of collaboration with our customers. Three weeks ago, a customer reached out to us with a design proposal for the main &amp;quot;Applications&amp;quot; view. Within three weeks it&#39;s not only been implemented, but is now live, running in FlowFuse Cloud, and available in FlowFuse 2.6.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of new &amp;quot;Applications&amp;quot; view for a given Team in FlowFuse.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-applications-view.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of new &amp;quot;Applications&amp;quot; view for a given Team in FlowFuse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The improvement here is that we&#39;ve moved instances and devices to be shown as a maximum of three per row (rather than the one perviously) meaning you can see far more content at a glance, and hopefully, get to where you need to go in fewer clicks.&lt;/p&gt;
&lt;h3 id=&quot;import%2Fexport-blueprints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#import%2Fexport-blueprints&quot;&gt;Import/Export Blueprints&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the admin page for &amp;quot;Flow Blueprints&amp;quot; with the new &amp;quot;Import&amp;quot;/&amp;quot;Export&amp;quot; buttons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/blueprint-import-export.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the admin page for &amp;quot;Flow Blueprints&amp;quot; with the new &amp;quot;Import&amp;quot;/&amp;quot;Export&amp;quot; buttons&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Administrators of FlowFuse instances can now import and export Blueprints. This is the first stage of a larger feature set for Blueprints that will make it easier to share common flows and patterns across FlowFuse instances, and see many extensions to our &lt;a href=&quot;https://flowfuse.com/blueprints/&quot;&gt;Blueprint Library&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;multi-line-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#multi-line-environment-variables&quot;&gt;Multi-line Environment Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the &amp;quot;Environment Variables&amp;quot; table in the Instance&#39;s Settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multiline-env-vars.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the &amp;quot;Environment Variables&amp;quot; table in an Instance&#39;s Settings&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We now support the use of multi-line environment variables for your Node-RED instances running on FlowFuse. This unlocks the ability to store certs or multi-line values like JSON as environment variables.&lt;/p&gt;
&lt;p&gt;We&#39;ve also improved the &lt;code&gt;.env&lt;/code&gt; importing to support the use of multi-line values too.&lt;/p&gt;
&lt;h3 id=&quot;and-much-more...&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#and-much-more...&quot;&gt;And Much More...&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For a full list of everything that went into our 2.6 release, you can check out the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.6.0&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. We&#39;re always interested in your thoughts about FlowFuse too. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#self-hosted&quot;&gt;Self-Hosted&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes. You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The quickest and easiest way to get started with FlowFuse is on our own hosted instance, FlowFuse Cloud: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; now, and you&#39;ll have your own Node-RED instances running in the Cloud within minutes.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;, then there is nothing you need to do - it&#39;s already running 2.6, and you may have already been playing with the new features.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/07/flowfuse-2-6-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/</id>
        <title>Node-RED Dashboard Formally Deprecated</title>
        <summary>It has just been announced that the predecessor to FlowFuse&#39;s Dashboard, Node-RED Dashboard, has been formally deprecated. Find out how FlowFuse Dashboard can help you build your Dashboards, and what we have planned in the near future.</summary>
        <updated>2024-06-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Dave Conway-Jones, the lead maintainer of Node-RED Dashboard, has &lt;a href=&quot;https://discourse.nodered.org/t/node-red-dashboard-v1-deprecation-notice/89006&quot;&gt;just announced&lt;/a&gt; that Node-RED Dashboard has been formally deprecated, meaning there will be no further development activity on the project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard&lt;/a&gt; (also known as Node-RED Dashboard 2.0) is a natural successor to Node-RED Dashboard, and in this article, we detail what FlowFuse Dashboard offers, and how you can get started.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-new-in-dashboard-2.0%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#what&#39;s-new-in-dashboard-2.0%3F&quot;&gt;What&#39;s new in Dashboard 2.0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not only have we made significant efforts to ensure that FlowFuse Dashboard has as much feature parity with Node-RED Dashboard as possible, but we&#39;ve also introduced a number of new features that we think you&#39;ll love, some highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi Tenancy:&lt;/strong&gt; A big change from Node-RED Dashboard is the introduction of multi-tenancy features. This allows you to build Dashboards that are unique to each user that interacts with your flows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsive Layouts:&lt;/strong&gt; FlowFuse Dashboard is built with a responsive layout in mind, meaning that your Dashboards will automatically adjust to the screen size of the device they are being viewed on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New Nodes:&lt;/strong&gt; We&#39;ve introduced a five new nodes; &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-button-group.html&quot;&gt;Button Group&lt;/a&gt;, &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-radio-group.html&quot;&gt;Radio Group&lt;/a&gt;, &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-file-input.html&quot;&gt;File Upload&lt;/a&gt;, &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-event.html&quot;&gt;Event&lt;/a&gt; and &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-table.html&quot;&gt;Table&lt;/a&gt; to help you build your Dashboards, without needing to write custom code, or depend on third-party libraries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directly Install on Mobile:&lt;/strong&gt; FlowFuse Dashboard is built as a Progressive Web App (PWA), this means that you&#39;re able to install it directly onto your mobile device as if it were a native mobile application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vuetify Framework:&lt;/strong&gt; FlowFuse Dashboard is built on VueJS, and with that, we made the decision to integrate in &lt;a href=&quot;https://vuetifyjs.com/en/components/all/#containment&quot;&gt;Vuetify&lt;/a&gt;, a very rich collection of functional UI widgets. All of these widgets are available, by default when you want to build your own custom widgets in a &lt;code&gt;ui-template&lt;/code&gt; node.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-we-have-planned&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#what-we-have-planned&quot;&gt;What we have planned&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are actively investing into the development of FlowFuse Dashboard, and releasing new features and updates on a regular basis. We have a public &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Project Management Board&lt;/a&gt; that show exactly what we&#39;re working on, and what we have planned in the near future. Some particular highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visual Layout Editor:&lt;/strong&gt; This would be the biggest improvement to building dashboards in Node-RED. We&#39;re aiming for a fully interactive front-end to help you design your Dashboard layouts. This would live in your Dashboard itself, no more needing to switch between the Node-RED Editor and your Dashboard to sanity check changes. You can see more details &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/30&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diversity of Data Visualisation:&lt;/strong&gt; We are planning to provide a richer ecosystem of data visualisations. We&#39;re also likely to be switching to &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/782&quot;&gt;Apache eCharts&lt;/a&gt; (subject to further investigation), and are considering a &lt;code&gt;ui-template&lt;/code&gt;-type node that can be used to build &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/58&quot;&gt;custom charts&lt;/a&gt; too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Parity:&lt;/strong&gt; Whilst we&#39;ve covered there vast majority of Dashboard 1.0 features, we&#39;ve still got a little bit to go, in particular, the most requested features we have are  &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/555&quot;&gt;programmatic (mustache) title and labels&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there are any other features you&#39;d like to see, please do open a &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/new/choose&quot;&gt;Feature Request&lt;/a&gt;, and we&#39;ll do our best to accommodate.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-with-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#getting-started-with-flowfuse-dashboard&quot;&gt;Getting Started with FlowFuse Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re ready to get started with FlowFuse Dashboard, you can install it directly from the Node-RED Palette Manager. Simply search for &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; and install the latest version.&lt;/p&gt;
&lt;p&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;A short recording to show how easy it is to setup your first dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://dashboard.flowfuse.com/assets/getting-started.DHDsIsZl.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;
&lt;em&gt;A short recording to show how easy it is to setup your first dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Getting started is as easy as dropping on your first node. FlowFuse Dashboard will automatically set you up with a default group, page, theme and underlying Dashboard configuration.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#resources&quot;&gt;Resources&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have a comprehensive &lt;a href=&quot;https://dashboard.flowfuse.com/getting-started.html&quot;&gt;Getting Started Guide&lt;/a&gt; that will walk you through the process of setting up your first Dashboard. You can download our &lt;a href=&quot;https://dashboard.flowfuse.com/#download-our-e-book&quot;&gt;&amp;quot;Ultimate Guide&amp;quot; eBook&lt;/a&gt; too.&lt;/p&gt;
&lt;h3 id=&quot;dashboard-workshop&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#dashboard-workshop&quot;&gt;Dashboard Workshop&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ll running a &lt;a href=&quot;https://flowfuse.com/webinars/2024/workshop-dashboard/&quot;&gt;Workshop&lt;/a&gt; on July 2nd, where we will be covering a collection of useful tips and design patterns to help you get the most out of Dashboard.&lt;/p&gt;
&lt;p&gt;The recording will also be available on the &lt;a href=&quot;https://www.youtube.com/@FlowFuseInc&quot;&gt;FlowFuse YouTube channel&lt;/a&gt; after the event.&lt;/p&gt;
&lt;h2 id=&quot;migrating-to-flowfuse-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#migrating-to-flowfuse-dashboard&quot;&gt;Migrating to FlowFuse Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re looking to migrate your existing Node-RED Dashboard flows to FlowFuse Dashboard, we have a &lt;a href=&quot;https://flowfuse.com/platform/dashboard/#migration-service&quot;&gt;Migration Guide&lt;/a&gt; that details all of the features and properties that have, and haven&#39;t, been migrated into FlowFuse Dashboard.&lt;/p&gt;
&lt;p&gt;It&#39;s worth noting that FlowFuse Dashboard &lt;em&gt;will&lt;/em&gt; run side-by-side with the original Node-RED Dashboard, so you can take your time to migrate your flows over, and do so, piece-by-piece.&lt;/p&gt;
&lt;p&gt;This week, we also made available the first iteration of the &lt;a href=&quot;https://flowfuse.com/platform/dashboard/#migration-service&quot;&gt;Dashboard Migration Service&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Dashboard Migration Service available on FlowFuse&#39;s website&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-migration-service.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the Dashboard Migration Service available on FlowFuse&#39;s website&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Currently, it&#39;ll convert your &lt;code&gt;ui_tab&lt;/code&gt;, &lt;code&gt;ui_group&lt;/code&gt; nodes, and setup your new &lt;code&gt;ui-theme&lt;/code&gt; and &lt;code&gt;ui-base&lt;/code&gt; nodes for you. We&#39;ll be extending this over time, and eventually hope to auto-convert most of your existing Dashboard 1.0 flows.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-1-deprecated/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re really excited to see what you can build with FlowFuse Dashboard, and we&#39;re here to help you every step of the way. If you have any questions, please do reach out to us on the &lt;a href=&quot;https://discourse.nodered.org/tag/dashboard-2&quot;&gt;Node-RED Community Forum&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in contributing and extending FlowFuse Dashboard, we&#39;re very open to Pull Requests, and have a detailed contributing guide you can take a look at &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/</id>
        <title>Interacting with Google Sheets from Node-RED</title>
        <summary>Guide to learn how to write, read, update and delete data in Google sheet using Node-RED.</summary>
        <updated>2024-06-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever needed to integrate Google Sheets with your Node-RED application to track and manage data seamlessly? This guide will walk you through the process of integrating Google Sheets with Node-RED, enabling you to write, read, update, and delete data effortlessly.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-google-sheet%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#what-is-the-google-sheet%3F&quot;&gt;What is the Google Sheet?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/sheets/about/&quot;&gt;Google Sheets&lt;/a&gt; is a cloud-based spreadsheet application developed by Google. It allows users to create, edit, and collaborate on spreadsheets in real-time over the Internet. This makes it an ideal option for easily and securely collaborating on data that is not large in size. In businesses, Google Sheets is commonly used for tasks such as analyzing daily profits, tracking expenses, and managing collaborative projects. However, for products or services with large user bases, businesses often prefer using databases, which are recommended for efficiently managing and scaling data operations.&lt;/p&gt;
&lt;h2 id=&quot;prequisite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#prequisite&quot;&gt;Prequisite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before proceeding, make sure you have installed the following node from the pallet manager.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-google-sheets&quot;&gt;node-red-contrib-google-sheets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;interacting-with-google-sheets-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#interacting-with-google-sheets-with-node-red&quot;&gt;Interacting with Google Sheets with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To integrate Google Sheets with our application we must first enable the Google Sheets API, and create the service account in the Google Cloud, before proceeding, make sure you have the Google Cloud account created.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open your browser and go to &lt;a href=&quot;https://console.cloud.google.com/projectselector2/apis/library/sheets?supportedpurview=project&amp;amp;authuser=0&quot;&gt;Service accounts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a new project by clicking the &amp;quot;CREATE PROJECT&amp;quot; button in the top right corner. Enter the project details such as project name and organization.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;CREATE PROJECT&#39; button&quot; alt=&quot;Screenshot showing the &#39;CREATE PROJECT&#39; button&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the Form to create the project&quot; alt=&quot;&amp;quot;Screenshot showing the Form to create the project&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Go to the main menu by clicking the menu icon in the top left, then select &amp;quot;APIs &amp;amp; Services.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;APIs &amp; Services&#39; option from the main menu&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;APIs &amp;amp; Services&#39; from the menu&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Click on &amp;quot;Enable APIs and Services&amp;quot; in the header.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Enable APIs and Services&#39; option&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Enable APIs and Services&#39; option&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_4.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;In the search bar, type &amp;quot;Google Sheets&amp;quot; and select it from the results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the Google Sheet in the search result&quot; alt=&quot;&amp;quot;Screenshot showing the Google Sheet in the search result&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Click the &amp;quot;Enable&amp;quot; button to enable the Google Sheets API.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Enable&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Enable&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_6.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Go back to the main menu and click on &amp;quot;IAM &amp;amp; Admin,&amp;quot; then select &amp;quot;Service Accounts&amp;quot; from the left sidebar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;IAM &amp; Admin&#39; from the menu&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;IAM &amp;amp; Admin&#39; from the menu&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_7.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Click on &amp;quot;Create Service Account&amp;quot; in the header. Enter the necessary details and click &amp;quot;Create&amp;quot; to proceed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Create Service Account&#39; option&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Create Service Account&#39; option&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_8.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Create&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Create&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_9.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;Select the Role from the &amp;quot;Owner&amp;quot; and click on the &amp;quot;Continue&amp;quot; button.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Continue&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Continue&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_10.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;Click &amp;quot;Done.&amp;quot; Make sure to copy the generated service account email and save it for later use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Done&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Done&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_11.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the created service account email&quot; alt=&quot;&amp;quot;Screenshot showing the created service account email&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_14.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;11&quot;&gt;
&lt;li&gt;To generate a private key, click on the three dots icon on the right of the newly created service account and select &amp;quot;Manage keys.&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the three dot icon&quot; alt=&quot;&amp;quot;Screenshot showing the three dot icon&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_15.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;Click on &amp;quot;Add key,&amp;quot; choose &amp;quot;Create new key,&amp;quot; select &amp;quot;JSON&amp;quot; as the key type, and click &amp;quot;Create.&amp;quot; Your private key will be generated and downloaded.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;Add key&#39; and the &#39;Create new key&#39;&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Add key&#39; and the &#39;Create new key&#39;&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_15.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the &#39;JSON&#39; option and &#39;Create new key&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;JSON&#39; option and &#39;Create new key&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete-page_13.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-google-sheet-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#configuring-the-google-sheet-node&quot;&gt;Configuring the Google Sheet Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before proceeding, ensure you have added the &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;environment variable&lt;/a&gt; for the private key that was generated. Additionally, grant the editor access to the sheet you want to interact with for that service account email we created in the above section.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a GSheet node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the node and click on the pencil icon next to &amp;quot;creds.&amp;quot;&lt;/li&gt;
&lt;li&gt;Enter the environment variable added for the private key in the &amp;quot;creds&amp;quot; field and click &amp;quot;Add.&amp;quot;&lt;/li&gt;
&lt;li&gt;Go to the Google Sheet you want to interact with and copy its ID from the URL. The URL will be in this format: &lt;code&gt;https://docs.google.com/spreadsheets/d/&amp;lt;id_of_sheet&amp;gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Return to your Node-RED instance, double-click on the GSheet node again, and paste the spreadsheet ID into the &amp;quot;SpreadsheetID&amp;quot; field.&lt;/li&gt;
&lt;li&gt;Enter the range of cells you want to work with using the syntax &lt;code&gt;&amp;lt;sheetname!first-cell-name:last-cell-name&amp;gt;&lt;/code&gt;. For example, use &lt;code&gt;Sheet1!A1:C3&lt;/code&gt; to specify that you are working with the &amp;quot;Sheet1&amp;quot; tab, starting from cell &amp;quot;A1&amp;quot; to cell &amp;quot;C3&amp;quot;. This syntax allows you to define specific ranges such as a row (&lt;code&gt;A1:A5&lt;/code&gt;), a column (&lt;code&gt;A1:E1&lt;/code&gt;), or a block (&lt;code&gt;A1:C3&lt;/code&gt;) within the spreadsheet.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;writing-data-to-cells&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#writing-data-to-cells&quot;&gt;Writing Data to Cells&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For demonstration purposes, I will write simulated sensor data which includes a timestamp and sensor data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Inject node onto the canvas, and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;[$moment().format(), $random() * 100]&lt;/code&gt; as a JSONata expression, and set it to repeat every 3 seconds of interval.&lt;/li&gt;
&lt;li&gt;Double-click on the GSheet node, select the method to &amp;quot;Append Row&amp;quot; set the range to &lt;code&gt;&amp;lt;sheetname&amp;gt;!A2&lt;/code&gt;, and replace &lt;code&gt;sheetname&lt;/code&gt; with the name of your sheet. I have defined cell A2 because I want to start writing data from cell A2.&lt;/li&gt;
&lt;li&gt;Drag the Debug node onto the canvas, which will help in debugging in case of any error.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the GSheet node, and the output of the GSheet node to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the write operation&quot; alt=&quot;&amp;quot;Image showing the write operation&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-write.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This flow generates a timestamp and a random number. The data is formatted as an array because I want the timestamp (the first item of the array) to be placed in column A and the random number (the second item of the array) to be placed in column B. If you want to insert data into additional columns, you can add more items to the array. For example, if you add a third item to the array, it will be placed in column C, a fourth item will be placed in column D, and so on.&lt;/p&gt;
&lt;h3 id=&quot;reading-data-from-cells&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#reading-data-from-cells&quot;&gt;Reading Data from Cells&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag another GSheet node onto the canvas, and set the method to &amp;quot;Get Cells&amp;quot; and the range to &lt;code&gt;&amp;lt;sheetname&amp;gt;!A2:C1000&lt;/code&gt;, as I wanted to read data from cell A2 to the next 1000 cells.&lt;/li&gt;
&lt;li&gt;Drag a Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the GSheet node, and the output of the GSheet node to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the read operation&quot; alt=&quot;&amp;quot;Image showing the read operation&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-read.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;updating-data-of-cells&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#updating-data-of-cells&quot;&gt;Updating Data of Cells&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto the canvas, and set the updated value as the &lt;code&gt;msg.payload&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Drag another GSheet node onto the canvas, and set the method to &amp;quot;Update Cells&amp;quot; and the range to &lt;code&gt;&amp;lt;sheetname&amp;gt;!A2&lt;/code&gt;, as I wanted to update the value of cell A2.&lt;/li&gt;
&lt;li&gt;Drag a Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the GSheet node, and the output of the GSheet node to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the update operation&quot; alt=&quot;&amp;quot;Image showing the update operation&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-update.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;deleting-data-from-cells&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#deleting-data-from-cells&quot;&gt;Deleting Data from Cells&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an Inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag another GSheet node onto the canvas, and set the method to &amp;quot;Clear Cells&amp;quot; and the range to &lt;code&gt;&amp;lt;sheetname&amp;gt;!A2:C50&lt;/code&gt;, as I wanted to clear the first 50 records.&lt;/li&gt;
&lt;li&gt;Drag a Debug node onto the canvas.&lt;/li&gt;
&lt;li&gt;Connect the output of the Inject node to the input of the GSheet node, and the output of the GSheet node to the input of the Debug node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing the delete operation&quot; alt=&quot;&amp;quot;Image showing the delete operation&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/interacting-with-google-sheet-from-node-red-delete.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Below I have provided the complete flow that we have built through the guide, make sure to replace the environment variable with your environment variable added for the private key.&lt;/p&gt;
&lt;div id=&quot;nr-flow-183&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow183 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;7d0282761979574c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Wrting data to the cells&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[&#92;&#92;t    $moment(),&#92;&#92;t    $random()*100&#92;&#92;t    &#92;&#92;t]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:240,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;eda23377d98e1a51&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;eda23377d98e1a51&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;GSheet&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;creds&#92;&quot;:&#92;&quot;d38cb80ae8574ea6&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sheet&#92;&quot;:&#92;&quot;1TEEShkuxxrb3WH4NTFyk1COeDyWpgX1w6HN08ZezC7s&#92;&quot;,&#92;&quot;cells&#92;&quot;:&#92;&quot;Sheet1!A2:C1000&#92;&quot;,&#92;&quot;flatten&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3e670f575b8227d0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3e670f575b8227d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2c916b1d5c10dffe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read the cells data&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;941c7fe7c7dbcbcd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;941c7fe7c7dbcbcd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;GSheet&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;creds&#92;&quot;:&#92;&quot;d38cb80ae8574ea6&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;get&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sheet&#92;&quot;:&#92;&quot;1TEEShkuxxrb3WH4NTFyk1COeDyWpgX1w6HN08ZezC7s&#92;&quot;,&#92;&quot;cells&#92;&quot;:&#92;&quot;Sheet1!A2:C3&#92;&quot;,&#92;&quot;flatten&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f910d7637788361a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f910d7637788361a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c20997333f9d4bda&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Updating the cells data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[&#92;&#92;t   &#92;&#92;&#92;&quot;none&#92;&#92;&#92;&quot;,&#92;&#92;t   &#92;&#92;&#92;&quot;none&#92;&#92;&#92;&quot;&#92;&#92;t    &#92;&#92;t]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;jsonata&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d9ca2a1e0614f764&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9ca2a1e0614f764&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;GSheet&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;creds&#92;&quot;:&#92;&quot;d38cb80ae8574ea6&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;update&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sheet&#92;&quot;:&#92;&quot;1TEEShkuxxrb3WH4NTFyk1COeDyWpgX1w6HN08ZezC7s&#92;&quot;,&#92;&quot;cells&#92;&quot;:&#92;&quot;Sheet1!A35&#92;&quot;,&#92;&quot;flatten&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9febe629870b7a54&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9febe629870b7a54&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c9ceec9844fa74a9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Deleting the cells data&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b9cef9c376d1bea3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9cef9c376d1bea3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;GSheet&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;creds&#92;&quot;:&#92;&quot;d38cb80ae8574ea6&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;clear&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sheet&#92;&quot;:&#92;&quot;1TEEShkuxxrb3WH4NTFyk1COeDyWpgX1w6HN08ZezC7s&#92;&quot;,&#92;&quot;cells&#92;&quot;:&#92;&quot;Sheet1!A2:C20&#92;&quot;,&#92;&quot;flatten&#92;&quot;:false,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a1766b498efb50f4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a1766b498efb50f4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;baa50b8a4762ec1f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 4&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d38cb80ae8574ea6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;gauth&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Unknown&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow183.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-183&#39;) })&lt;/script&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/interacting-with-google-sheet-from-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide demonstrated how to integrate Google Sheets with Node-RED for streamlined data management. We covered setting up the Google Sheets API, configuring Node-RED to interact with sheets, and performing actions like writing, reading, updating, and deleting data.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/</id>
        <title>Multi-Tenancy available for everyone with FlowFuse&#39;s Dashboard 2.0</title>
        <summary>With a recent update in Node-RED Dashboard 2.0, we&#39;ve made some significant changes to the multi-tenancy feature set. Discover what&#39;s new and how it can benefit your projects.</summary>
        <updated>2024-06-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse Dashboard has featured multi-tenancy features through the FlowFuse User Addon. This made user based applications available only to specific FlowFuse team tiers and customers. However, the Node-RED community wanted to use the same feature set in cases FlowFuse didn&#39;t consider initially. Taking this feedback on board, today we announce some significant changes to how you can build Dashboards with multi-tenancy in mind.&lt;/p&gt;
&lt;p&gt;Having taken that feedback on board, we&#39;ve made some significant changes to how you can build Dashboards with multi-tenancy in mind.&lt;/p&gt;
&lt;p&gt;A quick summary of the changes are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Socket constraints moved to core Dashboard:&lt;/strong&gt; The ability to constrain communications to a specific client (using the &lt;code&gt;msg._client.socketId&lt;/code&gt;) has been moved to the core of Dashboard 2.0, and is no longer a feature of the FlowFuse User Addon. As such, it&#39;s available to &lt;em&gt;all&lt;/em&gt; users, for &lt;em&gt;all&lt;/em&gt; node types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse User Addon now Source Available:&lt;/strong&gt; The addon is available to install in &lt;em&gt;any&lt;/em&gt; instances of Node-RED running on FlowFuse, so that&#39;s all team tiers on FlowFuse Cloud, and any self-hosted instances of FlowFuse too. It is available to install from Node-RED&#39;s Palette Manager.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Auth Plugin:&lt;/strong&gt; Release of the first community-created Auth Plugin for Dashboard for adding a &lt;code&gt;user&lt;/code&gt; object when authenticating with Cloudflare. (See more details and install the plugin &lt;a href=&quot;https://flows.nodered.org/node/@fullmetal-fred/node-red-dashboard-2-cloudflare-auth&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;using-client-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#using-client-data&quot;&gt;Using Client Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Available since our &lt;code&gt;1.10.0&lt;/code&gt; release of Dashboard, we have a new sidebar tab - &amp;quot;Client Data&amp;quot;.&lt;/p&gt;
&lt;p&gt;This new tab acts as a portal to control whether data about the connected clients is included in any events emitted in the Node-RED editor (appended into &lt;code&gt;msg._client&lt;/code&gt;). You can then use the &amp;quot;Accept CLient Data&amp;quot; options to define which nodes accept that data as a constraint for communication.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the new &amp;quot;Client Data&amp;quot; sidebar available with Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-multi-tenancy-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing the new &amp;quot;Client Data&amp;quot; sidebar available with Dashboard&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this case, if we send a &lt;code&gt;msg&lt;/code&gt; to any &lt;code&gt;ui-notification&lt;/code&gt; or &lt;code&gt;ui-control&lt;/code&gt; which a specified &lt;code&gt;msg._client.socketId&lt;/code&gt;, then that &lt;code&gt;msg&lt;/code&gt; will &lt;em&gt;only&lt;/em&gt; be sent to the relevant socket connection.&lt;/p&gt;
&lt;h2 id=&quot;building-multi-tenant-dashboards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#building-multi-tenant-dashboards&quot;&gt;Building Multi-Tenant Dashboards&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have introduced a new section to our documentation on &lt;a href=&quot;https://dashboard.flowfuse.com/getting-started.html#design-patterns&quot;&gt;Design Patterns&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To summarise briefly, we now consider there to be two primary design patterns when building with Dashboard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single Source of Truth&lt;/strong&gt;: All users of your Dashboard will see the same data. This is useful for industrial IoT or Home Automation applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Tenancy&lt;/strong&gt;: Data shown in a particular widget is unique to a given client/session/user. This represents a more traditional web application, where each user has their own session and associated data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that these patterns can be intertwined, some widgets on a screen may be driven by &amp;quot;Single Source of Truth&amp;quot;, and others by &amp;quot;Multi-Tenancy&amp;quot;.&lt;/p&gt;
&lt;h4 id=&quot;building-a-single-source-of-truth-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#building-a-single-source-of-truth-dashboard&quot;&gt;Building a Single Source of Truth Dashboard&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example flow diagram to show the flow of data in a &amp;quot;Single Source of Truth&amp;quot; architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/design-pattern-single.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Example flow diagram to show the flow of data in a &amp;quot;Single Source of Truth&amp;quot; architecture&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Data can be sent to these widgets at any time, when a user connects to the Dashboard, the respective widget will load the relevant data from the centralised data source in Node-RED and show it to the user.&lt;/p&gt;
&lt;h4 id=&quot;building-a-multi-tenancy-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#building-a-multi-tenancy-dashboard&quot;&gt;Building a Multi-Tenancy Dashboard&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example flow diagram to show the flow of data in a &amp;quot;Multi-Tenancy&amp;quot; architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/design-pattern-client.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Example flow diagram to show the flow of data in a &amp;quot;Multi-Tenancy&amp;quot; architecture&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this pattern, a very useful node is the &lt;code&gt;ui-event&lt;/code&gt; node which fires a &lt;code&gt;msg&lt;/code&gt; when a user views a page. This &lt;code&gt;msg&lt;/code&gt; will contain a &lt;code&gt;msg._client&lt;/code&gt; object, detailing the client&#39;s connection.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;_client&lt;/code&gt; object contains the &lt;code&gt;socketId&lt;/code&gt; of the user (and potentially more depending on any &lt;a href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#authentication-plugins&quot;&gt;Authentication plugins&lt;/a&gt; used). This &lt;code&gt;msg&lt;/code&gt; can then be passed through to any other widget, and if configured to &amp;quot;Accept Client Constraints&amp;quot; that &lt;code&gt;msg&lt;/code&gt; will only be sent to the specified client.&lt;/p&gt;
&lt;h2 id=&quot;authentication-plugins&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#authentication-plugins&quot;&gt;Authentication Plugins&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this release we&#39;ve also added a special category of plugins, &amp;quot;Authentication Plugins&amp;quot;.&lt;/p&gt;
&lt;p&gt;These plugins register themselves with Dashboard, and are permitted to add to the &lt;code&gt;msg._client&lt;/code&gt; object. This can be useful for adding additional information about end users, such as their user ID, e-mail address or username.&lt;/p&gt;
&lt;p&gt;This data can be used to constrain communications from Node-RED to a specific &lt;em&gt;user&lt;/em&gt; rather than just a &lt;em&gt;socket connection&lt;/em&gt;, which is far more reliable and secure.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing &amp;quot;FlowFuse User&amp;quot; being appended to `_client` by the FlowFuse User Addon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-include-client-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot showing &amp;quot;FlowFuse User&amp;quot; being appended to &lt;code&gt;_client&lt;/code&gt; by the FlowFuse User Addon&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Any active plugins you have installed, will also be detailed in the new &amp;quot;Client Data&amp;quot; sidebar (detailed above) so you can see which plugins are active and what data they are adding to the &lt;code&gt;msg._client&lt;/code&gt; object.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-user-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#flowfuse-user-addon&quot;&gt;FlowFuse User Addon&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whilst the plugin was first published a few months back, after hearing community feedback, we&#39;ve made changes and are now publishing the plugin to the Node_RED Palette Manager. As such, it&#39;s available to all users running FlowFuse.&lt;/p&gt;
&lt;p&gt;The addon appends a &lt;code&gt;user&lt;/code&gt; object to the &lt;code&gt;msg._client&lt;/code&gt; object, populated with the details of the FlowFuse user performing the relevant actions in Dashboard. You can use this information to build multi-tenant Dashboards.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard-2-user-addon&quot;&gt;install the FlowFuse User Addon&lt;/a&gt; from the Palette Manager in the Node-RED editor.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Instance settings in FlowFuse to enable &amp;quot;FlowFuse User Authentication&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-instance-security.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot of the Instance settings in FlowFuse to enable &amp;quot;FlowFuse User Authentication&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s worth noting that instances must have &lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#enabling-flowfuse-user-authentication&quot;&gt;&amp;quot;FlowFuse User Authentication&amp;quot;&lt;/a&gt; switched on in the instance&#39;s settings.&lt;/p&gt;
&lt;h3 id=&quot;cloudfare-user-addon-(community-contribution)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#cloudfare-user-addon-(community-contribution)&quot;&gt;Cloudfare User Addon (Community Contribution)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re also thrilled to announce that the first community-contributed plugin has been &lt;a href=&quot;https://flows.nodered.org/node/@fullmetal-fred/node-red-dashboard-2-cloudflare-auth&quot;&gt;published&lt;/a&gt; which will append a &lt;code&gt;user&lt;/code&gt; object to the &lt;code&gt;msg._client&lt;/code&gt; object when authenticating with Cloudflare.&lt;/p&gt;
&lt;p&gt;A huge thanks to Fred Loucks (&lt;a href=&quot;https://github.com/fullmetal-fred&quot;&gt;@fullmetal-fred&lt;/a&gt; on GitHub) for his great contribution!&lt;/p&gt;
&lt;h2 id=&quot;build-multi-tenant-dashboards-with-flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/dashboard-multi-tenancy/#build-multi-tenant-dashboards-with-flowfuse-cloud&quot;&gt;Build Multi Tenant Dashboards with FlowFuse Cloud&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start by following our &lt;a href=&quot;https://dashboard.flowfuse.com/user/multi-tenancy.html#building-multi-tenant-dashboards&quot;&gt;Getting Started Guide&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/node-red-4-on-flowfuse-cloud/</id>
        <title>Node-RED 4: Bringing better collaboration to FlowFuse Cloud</title>
        <summary>Making use of the Multiplayer Mode to collaborate with your teams</summary>
        <updated>2024-06-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/node-red-4-on-flowfuse-cloud/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Node-RED 4.0 is the new major release of the project, which is at the heart of all we do at FlowFuse. It brings a range of new features that continue to make Node-RED the first choice for low-code development.&lt;/p&gt;
&lt;p&gt;As &lt;a href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/&quot;&gt;we wrote recently&lt;/a&gt;, our product mission statement is to provide the best way to build, manage and deploy Node-RED applications at scale, in reliable and secure production environments. This drives the work we do both within the FlowFuse platform and our contributions back into the Node-RED project.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://nodered.org/blog/2024/06/20/version-4-0-released&quot;&gt;Node-RED 4.0 release&lt;/a&gt; includes some of our recent contributions to improve the Build part of that mission - more specifically around the Collaborative Development part.&lt;/p&gt;
&lt;p&gt;Within FlowFuse we already have features such as the &lt;a href=&quot;https://flowfuse.com/docs/user/shared-library/&quot;&gt;Team Library&lt;/a&gt; that help team members share their flows with each other. That works well when working across separate Node-RED instances, but we wanted to improve the experience when working with the &lt;em&gt;same&lt;/em&gt; Node-RED instance.&lt;/p&gt;
&lt;p&gt;There has been a common complaint from users in the community on how Node-RED handles multiple users editing flows at the same time. Our goal is to make collaboration as simple and natural as possible and Node-RED 4.0 brings us a big step forward.&lt;/p&gt;
&lt;h2 id=&quot;multiplayer-mode&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/node-red-4-on-flowfuse-cloud/#multiplayer-mode&quot;&gt;Multiplayer Mode&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A key problem has been not knowing what other users were doing in the editor; not knowing that someone else was making changes until they deploy them, causing you to be interrupted in your own work to figure out how to pull their changes into your editor.&lt;/p&gt;
&lt;p&gt;The new Node-RED Multiplayer Mode helps to address this by showing you who else has the editor open and &#39;where&#39; they are in the editor - such as which tab they have open, or if they are currently editing a node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of Node-RED multiplayer in action&quot; alt=&quot;&amp;quot;Screenshot of Node-RED multiplayer in action&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr4-multiplayer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This is just the first step to our eventual goal of being able to see the changes others are making in real-time.&lt;/p&gt;
&lt;h2 id=&quot;concurrent-deploy-handling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/node-red-4-on-flowfuse-cloud/#concurrent-deploy-handling&quot;&gt;Concurrent Deploy Handling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A second thread to this work has been to improve the workflow when someone deploys changes whilst you&#39;re busy working on your own flows.&lt;/p&gt;
&lt;p&gt;With previous versions of Node-RED, each time someone deployed changes, you would receive a notification you couldn&#39;t ignore - having to deal it before you could continue what you were doing. Getting one notification wasn&#39;t so bad, but if your team mate was being particularly productive, they might be hitting the deploy button regularly - each time interrupting your own flow.&lt;/p&gt;
&lt;p&gt;With Node-RED 4.0, we&#39;ve made some small adjustments that should have a big impact. The notification that someone has deployed changes in the background is now much more discrete - and can be ignored entirely. Only when you want to deploy your changes will you need to merge in their changes first. This lets you stay in the zone whilst working, keeping the interruptions to a minimum.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the new background deploy notification&quot; alt=&quot;&amp;quot;Screenshot of the new background deploy notification&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr4-background-deploy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/node-red-4-on-flowfuse-cloud/#other-updates&quot;&gt;Other Updates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are of course many other great reasons to start using Node-RED 4.0. The &lt;a href=&quot;https://nodered.org/blog/2024/06/20/version-4-0-released&quot;&gt;community blog post&lt;/a&gt; describes all the other great features in this release.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/</id>
        <title>FlowFuse 2.5: New features to visualize snapshots, LDAP integration, and more</title>
        <summary>Enhancing security, visualization, and deployment flexibility.</summary>
        <updated>2024-06-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.5 introduces LDAP integration, snapshot comparison, extends the ability to preview flow to Blueprints, rounds out the management for snapshots, and allows you to point your own domain names at your FlowFuse instances.&lt;/p&gt;
&lt;h2 id=&quot;support-for-ldap-integration-%232558&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#support-for-ldap-integration-%232558&quot;&gt;Support for LDAP integration &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2558&quot;&gt;#2558&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In our commitment to making FlowFuse more versatile and secure, we&#39;ve introduced support for LDAP alongside our existing SAML SSO options. This has been a much requested feature that we are excited to release.  This allows organizations to manage user authentication seamlessly, leveraging their existing LDAP infrastructure. With this feature, you can ensure that access controls are robust and aligned with your company&#39;s security policies.&lt;/p&gt;
&lt;h2 id=&quot;compare-snapshots-visually-to-see-differences-%233624&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#compare-snapshots-visually-to-see-differences-%233624&quot;&gt;Compare Snapshots Visually to see differences &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3624&quot;&gt;#3624&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Keeping track of changes and updates has never been easier. With our new visual comparison tool, you can now compare snapshots and see the differences at a glance. This feature provides a clear, graphical representation of changes, making it simple to identify modifications and understand their impact.&lt;/p&gt;
&lt;h2 id=&quot;preview-blueprints-before-deployment-%233838&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#preview-blueprints-before-deployment-%233838&quot;&gt;Preview Blueprints before Deployment &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3838&quot;&gt;#3838&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Similarly to the feature to be able to compare snapshots we have enabled this same feature to allow users to preview team flows and blueprints prior to deploying.  This expedites the process when you are attempting to find the correct flow for your application.  We find that our users will be able to expedite the exploration of both their own team library and the blueprints.&lt;/p&gt;
&lt;h2 id=&quot;import-and-export-support-for-snapshots-%233628&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#import-and-export-support-for-snapshots-%233628&quot;&gt;Import and Export support for snapshots &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3628&quot;&gt;#3628&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing your Node-RED artifacts just got simpler with our new import and export support for snapshots. With just a few clicks, you can easily transfer configurations between deployments or back up your current setup. This feature is perfect for those who need to replicate environments within their own enterprise with multiple deployments or ensure their configurations are safely stored.&lt;/p&gt;
&lt;h2 id=&quot;deploy-dashboard-and-apis-running-on-flowfuse-via-your-own-domain-names-%23324&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#deploy-dashboard-and-apis-running-on-flowfuse-via-your-own-domain-names-%23324&quot;&gt;Deploy Dashboard and APIs running on Flowfuse via your own Domain Names &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/324&quot;&gt;#324&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Branding and accessibility are crucial, and with FlowFuse 2.5, you can now deploy dashboards and APIs on your own domain names. This enhancement allows you to present a consistent brand experience and makes it easier for users to access your services. Whether you&#39;re deploying internally or externally, this feature provides the flexibility you need.&lt;/p&gt;
&lt;h2 id=&quot;full-list-of-release-features-and-bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#full-list-of-release-features-and-bug-fixes&quot;&gt;Full list of release features and bug fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can view everything included in 2.5 on the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.5.0&quot;&gt;Github Release page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also regularly release updates to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; in between our monthly releases. You can follow the updates as they are made via our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;ChangeLog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 2.5.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/flowfuse-2-5-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/</id>
        <title>Working with MQTT in Node-RED: Complete Guide (2026)</title>
        <summary>Connect, subscribe, and publish MQTT messages in Node-RED</summary>
        <updated>2024-06-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;MQTT handles the messaging layer for most IoT deployments. Node-RED provides built-in nodes that connect to MQTT brokers, subscribe to topics, and publish messages—all through a visual interface.&lt;/p&gt;
&lt;p&gt;This guide walks through the configuration steps and common patterns you&#39;ll need for working implementations.&lt;/p&gt;
&lt;h2 id=&quot;what-you&#39;ll-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#what-you&#39;ll-need&quot;&gt;What You&#39;ll Need&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Instance&lt;/strong&gt;: You need Node-RED running somewhere. Easiest option is FlowFuse, grab a &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;free trial&lt;/a&gt; and you get a cloud-hosted instance ready to go. No server setup, no port forwarding hassles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQTT Broker&lt;/strong&gt;: You&#39;ll need an MQTT broker to handle message routing. If you&#39;re on FlowFuse Pro tier, you get a built-in MQTT broker service—no separate setup needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-connected&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#getting-connected&quot;&gt;Getting Connected&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED ships with MQTT nodes already installed. Open your Node-RED editor and look in the palette—you&#39;ll find &lt;strong&gt;mqtt-in&lt;/strong&gt; and &lt;strong&gt;mqtt-out&lt;/strong&gt; under the network section.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&#39;re using FlowFuse&#39;s managed MQTT broker, this is straightforward. Use the &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mqtt/mqtt-in/&quot;&gt;ff-mqtt-in&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/node-red/flowfuse/mqtt/mqtt-out/&quot;&gt;ff-mqtt-out&lt;/a&gt; nodes instead of the standard MQTT nodes. Simply drag one onto the canvas, and the connection to FlowFuse&#39;s broker will be configured automatically.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For any other broker, drag an &lt;strong&gt;mqtt-in&lt;/strong&gt; or &lt;strong&gt;mqtt-out&lt;/strong&gt; node onto your workspace. Double-click it to open the configuration panel.&lt;/p&gt;
&lt;p&gt;Click the pencil icon next to &lt;strong&gt;Server&lt;/strong&gt;. You&#39;ll see two tabs: Connection and Security.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Connection Tab&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT Connection Tab - Configure broker address, port, and TLS settings&quot; alt=&quot;MQTT broker connection configuration screen showing server address, port, and protocol settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-broker-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Server&lt;/strong&gt;: Enter your broker address (&lt;code&gt;broker.hivemq.com&lt;/code&gt; for testing, or your broker&#39;s hostname)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port&lt;/strong&gt;: Use &lt;code&gt;8883&lt;/code&gt; for encrypted connections, &lt;code&gt;1883&lt;/code&gt; for unencrypted&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable TLS&lt;/strong&gt;: Check this if you&#39;re using port 8883&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol&lt;/strong&gt;: Leave it at MQTT 3.1.1 unless you specifically need MQTT 5 features&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Security Tab&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT Security Tab - Enter credentials using environment variables for security&quot; alt=&quot;MQTT broker security configuration showing username and password fields&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-configuration-security-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Enter your username and password. For anything beyond local testing, use environment variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Put &lt;code&gt;${MQTT_USER}&lt;/code&gt; in the username field&lt;/li&gt;
&lt;li&gt;Put &lt;code&gt;${MQTT_PASSWORD}&lt;/code&gt; in the password field&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set these in your Node-RED settings or FlowFuse environment config&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;See &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt; for setup details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Click &lt;strong&gt;Add&lt;/strong&gt;, then &lt;strong&gt;Done&lt;/strong&gt;. Deploy your flow. If the node shows &amp;quot;connected&amp;quot; under it, you&#39;re in.&lt;/p&gt;
&lt;h2 id=&quot;publishing-data-to-a-topic-on-mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#publishing-data-to-a-topic-on-mqtt-broker&quot;&gt;Publishing Data to a Topic on MQTT Broker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The mqtt-out node sends data from Node-RED to your MQTT broker. Configure the topic, quality of service level, and retention settings to control how your messages are delivered.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;mqtt-out&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;mqtt-out&lt;/strong&gt; node and select your broker from the &lt;strong&gt;Server&lt;/strong&gt; dropdown.&lt;/li&gt;
&lt;li&gt;Enter your topic name in the &lt;strong&gt;Topic&lt;/strong&gt; field. Use forward slashes for hierarchy like &lt;code&gt;factory/line1/temp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;QoS&lt;/strong&gt; to &lt;strong&gt;2&lt;/strong&gt; for guaranteed delivery. Use &lt;strong&gt;1&lt;/strong&gt; if you can tolerate occasional duplicates, or &lt;strong&gt;0&lt;/strong&gt; for high-frequency data where missing readings don&#39;t matter.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Retain&lt;/strong&gt; if new subscribers should immediately receive the last published value.&lt;/li&gt;
&lt;li&gt;Connect your data source to the mqtt-out node&#39;s input. The node expects &lt;code&gt;msg.payload&lt;/code&gt; to contain your data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT-out Node Configuration&quot; alt=&quot;MQTT-out node configuration panel settings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-out.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;subscribing-to-a-topic-on-mqtt-broker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#subscribing-to-a-topic-on-mqtt-broker&quot;&gt;Subscribing to a Topic on MQTT Broker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The mqtt-in node receives messages from topics you specify. You can subscribe to specific topics or use wildcards to monitor multiple topics at once.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;mqtt-in&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click the &lt;strong&gt;mqtt-in&lt;/strong&gt; node and select your broker from the &lt;strong&gt;Server&lt;/strong&gt; dropdown.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;subscribe to a single topic&lt;/strong&gt; and enter the topic name in the &lt;strong&gt;Topic&lt;/strong&gt; field. You can use:
&lt;ul&gt;
&lt;li&gt;Specific topics: &lt;code&gt;factory/line1/temp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Single-level wildcard: &lt;code&gt;factory/+/temp&lt;/code&gt; (matches any value where + appears)&lt;/li&gt;
&lt;li&gt;Multi-level wildcard: &lt;code&gt;factory/#&lt;/code&gt; (matches everything under factory/)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;QoS&lt;/strong&gt; to &lt;strong&gt;2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Output&lt;/strong&gt; to &lt;strong&gt;auto-detect&lt;/strong&gt; (it parses JSON automatically and passes through other formats as strings).&lt;/li&gt;
&lt;li&gt;Connect the mqtt-in node&#39;s output to wherever you need the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT-in Node Configuration&quot; alt=&quot;MQTT-in node configuration showing subscription settings with topic field and QoS options&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-in-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For Dynamic Subscriptions:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you need to change subscriptions at runtime based on user input or system conditions, set &lt;strong&gt;Action&lt;/strong&gt; to &lt;strong&gt;dynamic&lt;/strong&gt; instead. You&#39;ll control subscriptions by sending messages with &lt;code&gt;msg.topic&lt;/code&gt; and &lt;code&gt;msg.action&lt;/code&gt; to the node&#39;s input.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT-in Dynamic Mode&quot; alt=&quot;MQTT-in node configured for dynamic subscription mode with empty topic field&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-in-dynamic.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To subscribe dynamically, send a message like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-212&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-212&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;factory/line1/temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;subscribe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-212&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;To unsubscribe:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-216&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-216&quot; class=&quot;language-javascript&quot;&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;factory/line1/temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unsubscribe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-216&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This is useful when users select which equipment to monitor from a dashboard, when topics depend on database queries or API responses, or when you need to add and remove subscriptions without redeploying your flow.&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#deploying-the-flow&quot;&gt;Deploying the Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Deploy your flow to activate the MQTT connection and start sending or receiving messages.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Deploy&lt;/strong&gt; button at the top-right corner.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Tip: Check the node status below each MQTT node. It will display &#39;connected&#39; if the connection is successful.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;MQTT Node Status - Green &#39;connected&#39; indicator confirms successful broker connection&quot; alt=&quot;MQTT nodes in Node-RED editor showing green connected status indicators below each node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt-node-status.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;best-practices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#best-practices&quot;&gt;Best Practices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Production MQTT deployments need more than basic configuration. These practices separate hobby projects from industrial-grade systems that run 24/7 without issues.&lt;/p&gt;
&lt;h3 id=&quot;security-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#security-first&quot;&gt;Security First&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Always use TLS encryption.&lt;/strong&gt; Unencrypted MQTT sends credentials and data in plain text across your network. Enable port 8883 with TLS on your broker, then check the &lt;strong&gt;Enable TLS&lt;/strong&gt; box in your Node-RED broker configuration. No exceptions for production systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never hardcode credentials.&lt;/strong&gt; Putting usernames and passwords directly in nodes means anyone with access to your flows can see them. Use environment variables instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Username: ${MQTT_USER}
Password: ${MQTT_PASS}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set these in your Node-RED settings file or FlowFuse environment configuration. See &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt; for the complete setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Implement access control on your broker.&lt;/strong&gt; Not every device needs to publish and subscribe to every topic. Configure your MQTT broker&#39;s ACL (Access Control List) to restrict clients based on their role. Sensors should only publish to their specific topics. Dashboard applications should only subscribe to what they display. This limits damage if credentials get compromised.&lt;/p&gt;
&lt;h3 id=&quot;choose-the-right-qos&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#choose-the-right-qos&quot;&gt;Choose the Right QoS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;QoS isn&#39;t a &amp;quot;set it and forget it&amp;quot; decision. Each level trades reliability against network overhead and latency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 0:&lt;/strong&gt; Fire and forget. Use for high-frequency sensor data where missing one reading doesn&#39;t matter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 1:&lt;/strong&gt; Guaranteed delivery, possible duplicates. Good for status updates and notifications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QoS 2:&lt;/strong&gt; Exactly once delivery with higher latency. Use for commands that trigger actions or critical transactions.&lt;/p&gt;
&lt;p&gt;Match QoS to your use case. Don&#39;t default everything to QoS 2 just to be safe—you&#39;ll waste bandwidth and add latency where it doesn&#39;t help.&lt;/p&gt;
&lt;h3 id=&quot;design-your-topic-hierarchy-properly&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#design-your-topic-hierarchy-properly&quot;&gt;Design Your Topic Hierarchy Properly&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your topic structure determines how easy it is to filter, subscribe, and scale your system. A hierarchical approach mirrors your physical setup and makes wildcards useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structure topics from general to specific:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;company/location/area/equipment/measurement
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Good hierarchy:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;acme/chicago/packaging/filler-01/temperature
acme/chicago/packaging/filler-01/pressure
acme/denver/assembly/robot-03/temperature
acme/denver/assembly/conveyor-02/speed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Poor hierarchy:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;temp-sensor-1
temp-sensor-2
pressure-sensor-1
line1-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The difference: with a proper hierarchy, you can subscribe at any level. Need all data from Chicago? Subscribe to &lt;code&gt;acme/chicago/#&lt;/code&gt;. Want temperature readings across all sites? Use &lt;code&gt;acme/+/+/+/temperature&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Flat topics force you to subscribe to dozens of individual topics and manage them manually. Hierarchical topics let the broker do the filtering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keep it simple:&lt;/strong&gt; Use lowercase, separate levels with forward slashes, use hyphens within names. Topics are paths, not sentences.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You now know how to connect Node-RED to MQTT brokers, publish data to topics, subscribe to incoming messages, and secure your deployment with TLS and proper credentials. That&#39;s the foundation.&lt;/p&gt;
&lt;p&gt;Go build something. Connect a sensor, route the data, display it somewhere useful. The patterns you&#39;ve learned here scale from a single device to entire factory floors.&lt;/p&gt;
&lt;p&gt;When you hit the limits of managing individual instances—tracking deployments, coordinating updates, maintaining uptime across sites—that&#39;s when tools like &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;FlowFuse&lt;/a&gt; become relevant. Until then, you have everything you need.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/</id>
        <title>Exploring Node-RED Dashboard 2.0 Widgets</title>
        <summary>A guide to using Node-RED 2.0 Widgets for Dashboard Development.</summary>
        <updated>2024-05-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;This guide delves into Node-RED Dashboard 2.0 widgets. It is a guide on how to build a Dashboard application, and will cover many of the widgets available today.&lt;/p&gt;
&lt;p&gt;If you&#39;re new to Dashboard 2.0, we recommend starting with the &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard 2.0&lt;/a&gt; guide and make sure to install it.&lt;/p&gt;
&lt;h2 id=&quot;what-are-widgets%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#what-are-widgets%3F&quot;&gt;What Are Widgets?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Widgets in Node-RED Dashboard 2.0 are the building blocks for creating a user interface. In Dashboard 2.0, you get a variety of widgets like forms, templates, buttons, and others to make different parts of your interface.&lt;/p&gt;
&lt;h2 id=&quot;building-applications-with-dashboard-2.0-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#building-applications-with-dashboard-2.0-widgets&quot;&gt;Building Applications with Dashboard 2.0 Widgets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Income-expense tracker build with dashboard 2.0&quot; alt=&quot;&amp;quot;Income-expense tracker build with dashboard 2.0&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-incom-expense-tracker-system.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Income-expense tracker build with dashboard 2.0&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this guide, we&#39;ll create a basic application to input expenses and income. This will then be displayed in a chart and table for analysis. The application will utilize a wide range of widgets available in Dashboard 2.0, helping you understand and use them confidently.&lt;/p&gt;
&lt;h3 id=&quot;adding-forms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#adding-forms&quot;&gt;Adding Forms&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For the income and expense submission, we&#39;ll incorporate a form using the &lt;strong&gt;ui-form&lt;/strong&gt; widget.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;ui-form&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it to access various widget properties and select the &lt;strong&gt;ui-group&lt;/strong&gt; where it should render.&lt;/li&gt;
&lt;li&gt;Add &amp;quot;date&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;amount&amp;quot;, and &amp;quot;note&amp;quot; form elements by clicking the &lt;strong&gt;+element&lt;/strong&gt; button at the bottom left.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying Income submission ui-form&#39;s configuration&quot; alt=&quot;&amp;quot;Screenshot displaying Income submission ui-form&#39;s configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-income-submission-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying Income submission ui-form&#39;s configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once you&#39;ve added the income submission form, repeat the process to add an expense submission form on another &lt;strong&gt;ui-page&lt;/strong&gt; and &lt;strong&gt;ui-group&lt;/strong&gt;. For more information on &lt;strong&gt;ui-form&lt;/strong&gt;, refer to the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-form.html&quot;&gt;ui-form docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying Expense submission ui-form&#39;s configuration&quot; alt=&quot;&amp;quot;Screenshot displaying Expense submission ui-form&#39;s configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-expense-submission-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying Expense submission ui-form&#39;s configuration&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;storing-form-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#storing-form-data&quot;&gt;Storing Form Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;ui-form&lt;/strong&gt; widget emits a payload object with key-value pairs of form elements upon submission. We&#39;ll store this data in a global context, If you are not familiar with Node-RED context, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/&quot;&gt;Understanding Node-RED varriables&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas and add the following code. This will store the submission in the &lt;code&gt;income&lt;/code&gt; global context variable, and then modify &lt;code&gt;msg.payload&lt;/code&gt; to pass on a notification to any further connected nodes.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-66&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-66&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Retrieve the existing &#39;income&#39; array from the global context, or initialize it as an empty array if it doesn&#39;t exist&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; income &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;income&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Push the incoming payload along with a &#39;type&#39; property set to &quot;income&quot; into the &#39;income&#39; array&lt;/span&gt;&lt;br /&gt;income&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;income&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Store the updated &#39;income&#39; array back into the global context&lt;/span&gt;&lt;br /&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;income&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; income&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the message payload to a confirmation message for notification&lt;/span&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Thank you for submitting income!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Return the modified message&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-66&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Similarly, you can do this for storing expense data submitted using the expense submission form.&lt;/p&gt;
&lt;h3 id=&quot;displaying-notifications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#displaying-notifications&quot;&gt;Displaying Notifications&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For displaying notifications on the dashboard, we&#39;ll utilize the &lt;strong&gt;ui-notification&lt;/strong&gt; widget, which emits notifications to the user&#39;s dashboard. It accepts &lt;code&gt;msg.payload&lt;/code&gt; which should be a string format or raw HTML/JavaScript for custom formatting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;ui-notification&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Set the position property to &lt;strong&gt;center&lt;/strong&gt;. You can also adjust colors or notification timeout by modifying the color and timeout properties. Please take a look at the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-notification.html#properties&quot;&gt;ui-notification docs&lt;/a&gt; for more information on &lt;strong&gt;ui-notification&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying ui-notification widgets configuration&quot; alt=&quot;&amp;quot;Screenshot displaying ui-notification widgets configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-notification-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying ui-notification widgets configuration&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;listening-for-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#listening-for-events&quot;&gt;Listening for events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Dashboard 2.0, the &lt;strong&gt;ui-event&lt;/strong&gt; widget allows you to listen to user behavior or events. It does not render any content or components on the dashboard. Currently, this widget only listens for page views (&lt;code&gt;$pageview&lt;/code&gt;) and leave (&lt;code&gt;$pageleave&lt;/code&gt;) events.&lt;/p&gt;
&lt;p&gt;With this, we can listen for page view and page leave events and trigger tasks based on those events. For instance, in our application, we will be displaying a table containing income and expense data, along with a chart. We&#39;ll update them when navigating to a new page or leaving a page.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ui-event&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and select the correct &lt;strong&gt;ui-base&lt;/strong&gt; of your application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information on ui-event refer to &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-event.html&quot;&gt;ui-event docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;retrieving-income-expense-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#retrieving-income-expense-data&quot;&gt;Retrieving Income-Expense Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our income-expense application, we will display the income and expenses in a single table.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to the JSONata expression below, which merges the income and expense arrays.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-133&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-133&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$globalContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;income&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$globalContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;expense&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-133&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;ui-event&lt;/strong&gt; widget to the input of the &lt;strong&gt;change&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node setting JSON expression to payload for retrieving and sorting data.&quot; alt=&quot;&amp;quot;Screenshot displaying the change node setting JSON expression to payload for retrieving and sorting data.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the change node setting JSON expression to payload for retrieving and sorting data.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;displaying-data-on-the-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#displaying-data-on-the-table&quot;&gt;Displaying Data on the Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To display data on the table, we use the &lt;strong&gt;ui-table&lt;/strong&gt; widget in Dashboard 2.0. This widget accepts an array of objects as input. The columns in the table correspond to the properties of the objects within the array, and each row represents a different object with values corresponding to those properties.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-table&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Create a new &lt;strong&gt;ui-page&lt;/strong&gt; and &lt;strong&gt;ui-group&lt;/strong&gt; for it.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;change&lt;/strong&gt; node to the input of the &lt;strong&gt;ui-table&lt;/strong&gt; widget.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the ui-table widget configuration&quot; alt=&quot;&amp;quot;Screenshot displaying the ui-table widget configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-table-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the ui-table widget configuration&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For more information on ui-table refer to &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-table.html&quot;&gt;ui-table docs&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;calculating-total-category-wise&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#calculating-total-category-wise&quot;&gt;Calculating total category-wise&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our application, we will display data on the chart, showing the total income and total expenses for analysis. In this section, we will calculate the total expenses and income using the function node.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the two &lt;strong&gt;change&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;For the first &lt;strong&gt;Change&lt;/strong&gt; node Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;global.income&lt;/code&gt; and &lt;code&gt;msg.topic&lt;/code&gt; to &amp;quot;income&amp;quot; and give it name &amp;quot;retrive income&amp;quot;. For the second &lt;strong&gt;Change&lt;/strong&gt; node, set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;global.expense&lt;/code&gt; and &lt;code&gt;msg.topic&lt;/code&gt; to &amp;quot;expense&amp;quot; and give that second change node name &amp;quot;retrive expense&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node retrieving income data from global context&quot; alt=&quot;&amp;quot;Screenshot displaying the change node retrieving income data from global context&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget-retrieve-income-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the change node retrieving income data from global context&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node retrieving expense data from global context&quot; alt=&quot;&amp;quot;Screenshot displaying the change node retrieving expense data from global context&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget-retrieve-expense-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the change node retrieving expense data from global context&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag the &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas and set &lt;code&gt;msg.payload.amount&lt;/code&gt; to the JSONata expression &lt;code&gt;$number(payload.amount)&lt;/code&gt; and give it name &amp;quot;Convert amount to number&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node converting amount to number&quot; alt=&quot;&amp;quot;Screenshot displaying the change node converting amount to number&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget-convert-amount-to-number-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the change node converting amount to number&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Join&lt;/strong&gt; node onto the canvas, select mode as &lt;strong&gt;reduced expression&lt;/strong&gt;, and set the &lt;strong&gt;Reduce exp&lt;/strong&gt; to &lt;code&gt;$A + payload.amount&lt;/code&gt;. Set Initial value to &lt;code&gt;0&lt;/code&gt;, and &lt;strong&gt;Fix-up exp&lt;/strong&gt; to &lt;code&gt;$A&lt;/code&gt;. Give this &lt;strong&gt;join&lt;/strong&gt; node the name &amp;quot;Calculate total&amp;quot;. This function operates similarly to using the javascript reduce method on an array to calculate the sum of its values. &lt;code&gt;$A&lt;/code&gt; stores the accumulated value, and with every incoming message payload, it adds the &lt;code&gt;payload.amount&lt;/code&gt; value to it, for more details on this refer to the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/join/&quot;&gt;core node docs on join node&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the join node calculating the total income and expense data&quot; alt=&quot;&amp;quot;Screenshot displaying the join node calculating the total income and expense data&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget-calculate-total-join-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the join node calculating the total income and expense data&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Drag an another join node onto the canvas set mode to manual, combine each to complete message, to create to array and After a number of message parts to 2 and give it name &amp;quot;combine two objects into array&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the join node combining the income and expense object into the&quot; alt=&quot;&amp;quot;Screenshot displaying the join node combining the income and expense object into the array&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget-retrieve-combine-object-join-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the join node combining the income and expense object into the array&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;
&lt;p&gt;Connect the output of the &lt;strong&gt;ui-event&lt;/strong&gt; widget to the input of the &lt;strong&gt;Change&lt;/strong&gt; node named &amp;quot;Retrieve Income&amp;quot; and &amp;quot;Retrieve Expense&amp;quot;. Then, connect the outputs of the &amp;quot;Retrieve Income&amp;quot; and &amp;quot;Retrieve Expense&amp;quot; &lt;strong&gt;Change&lt;/strong&gt; nodes to the input of the &lt;strong&gt;Split&lt;/strong&gt; node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, connect the output of the &lt;strong&gt;Split&lt;/strong&gt; node to the &lt;strong&gt;Change&lt;/strong&gt; node named &amp;quot;Convert Amount to Number&amp;quot;. Afterward, connect the output of that &lt;strong&gt;Change&lt;/strong&gt; node to the input of the &lt;strong&gt;Join&lt;/strong&gt; node named &amp;quot;Calculate Total&amp;quot;. Finally, connect the output of the &amp;quot;Calculate Total&amp;quot; &lt;strong&gt;Join&lt;/strong&gt; node to the input of the &lt;strong&gt;Join&lt;/strong&gt; node named &amp;quot;Combine Objects into Array&amp;quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;displaying-data-on-the-chart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#displaying-data-on-the-chart&quot;&gt;Displaying data on the chart&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To display charts on the dashboard, we have to use the ui-chart widget which allows us to display different types of charts on a dashboard including linear, bar, scatter, etc. This accepts an array and object as input.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-chart&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on the widget and select Type as &lt;strong&gt;bar&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Configure the series to &lt;strong&gt;category&lt;/strong&gt; and the y-axis to &lt;strong&gt;amount&lt;/strong&gt;. This configuration informs the chart that the &lt;strong&gt;amount&lt;/strong&gt; property of the input objects will be plotted on the y-axis and category to the x-axis of the chart.&lt;/li&gt;
&lt;li&gt;Connect the output of the &lt;strong&gt;join&lt;/strong&gt; node named &amp;quot;Combine Objects into Array&amp;quot; to the &lt;strong&gt;ui-chart&lt;/strong&gt; widget&#39;s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the ui-chart widget&#39;s configuration&quot; alt=&quot;&amp;quot;Screenshot displaying the ui-chart widget&#39;s configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-chart-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Screenshot displaying the ui-chart widget&#39;s configuration&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;adding-custom-footer-with-ui-template&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#adding-custom-footer-with-ui-template&quot;&gt;Adding custom footer with ui-template&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the &lt;strong&gt;ui-template&lt;/strong&gt; widget, we can add a custom component to our app using Vue.js. It also allows adding custom CSS for the dashboard and lot of other things. For more information refer to &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html&quot;&gt;ui-template docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using this widget, we will add a footer to our application.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ui-template&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Set the widget type (scoped UI) that will render this widget on the entire dashboard, eliminating the need to add separate footers for each page of the dashboard.&lt;/li&gt;
&lt;li&gt;Insert the following vue.js code in the &lt;strong&gt;ui-template&lt;/strong&gt; widget.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-301&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-301&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Footer Component &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;footer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Description &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; the Income&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Expense Tracker &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      Welcome to our comprehensive income expense tracker&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; Take control &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; your finances by monitoring your income and&lt;br /&gt;      expenses effortlessly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; Our user&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;friendly &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;makes&lt;/span&gt; it simple to record transactions&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; categorize expenses&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; and&lt;br /&gt;      analyze your financial trends&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; With real&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;time insights into your spending habits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; you can make smarter financial&lt;br /&gt;      decisions and achieve your money goals faster&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Copyright Information &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;copyright&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Display Current Year and Copyright Information &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token number&quot;&gt;2024&lt;/span&gt; — &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;strong&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Vuetify&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;strong&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;template&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;style scoped&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Make the footer occupy all available space */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;footer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    background&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;238&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;238&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;238&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;130px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    text&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;align&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;14px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;copyright&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    margin&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;style&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-301&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the ui-template widget&#39;s configuration&quot; alt=&quot;&amp;quot;Screenshot displaying the ui-template widget&#39;s configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exploring-dashboard-2-widgets-template-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;deploying-your-application-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#deploying-your-application-flow&quot;&gt;Deploying your application flow&lt;/a&gt;&lt;/h3&gt;
&lt;div id=&quot;nr-flow-180&quot; style=&quot;height: 450px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow180 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;301c1fd8e29c3aae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Footer&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n  &amp;lt;!-- Footer Component --&amp;gt;&#92;&#92;n  &amp;lt;div class=&#92;&#92;&#92;&quot;footer&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n    &amp;lt;!-- Description of the Income-Expense Tracker --&amp;gt;&#92;&#92;n    &amp;lt;div&amp;gt;&#92;&#92;n      Welcome to our comprehensive income expense tracker! Take control of your finances by monitoring your income and&#92;&#92;n      expenses effortlessly. Our user-friendly interface makes it simple to record transactions, categorize expenses,&#92;&#92;n      and&#92;&#92;n      analyze your financial trends. With real-time insights into your spending habits, you can make smarter financial&#92;&#92;n      decisions and achieve your money goals faster.&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n    &amp;lt;!-- Copyright Information --&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;copyright&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n      &amp;lt;!-- Display Current Year and Copyright Information --&amp;gt;&#92;&#92;n     2024 — &amp;lt;strong&amp;gt;Vuetify&amp;lt;/strong&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n  &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;style scoped&amp;gt;&#92;&#92;n  /* Make the footer occupy all available space */&#92;&#92;n  .footer {&#92;&#92;n    position: absolute;&#92;&#92;n    bottom: 0;&#92;&#92;n    background-color: rgb(26, 26, 26);&#92;&#92;n    color: rgb(238, 238, 238);&#92;&#92;n    height: 130px;&#92;&#92;n    text-align: center;&#92;&#92;n    padding: 14px;&#92;&#92;n  }&#92;&#92;n&#92;&#92;n  .copyright {&#92;&#92;n    margin-top: 10px;&#92;&#92;n  }&#92;&#92;n&amp;lt;/style&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;widget:ui&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:910,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;342f3ee215d32fdc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;New Icome page&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;d028c878350d19e1&#92;&quot;,&#92;&quot;43e79bb77d718c95&#92;&quot;,&#92;&quot;5ba5d8bff1a77bea&#92;&quot;],&#92;&quot;x&#92;&quot;:274,&#92;&quot;y&#92;&quot;:279,&#92;&quot;w&#92;&quot;:752,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;d028c878350d19e1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-form&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;342f3ee215d32fdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Income Submission Form&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;961528943e1bb698&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Date&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Description&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;description&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Amount&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;amount&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;number&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Note&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;note&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:false,&#92;&quot;rows&#92;&quot;:null}],&#92;&quot;formValue&#92;&quot;:{&#92;&quot;date&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;description&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;amount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;note&#92;&quot;:&#92;&quot;&#92;&quot;},&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;submit&#92;&quot;:&#92;&quot;submit&#92;&quot;,&#92;&quot;cancel&#92;&quot;:&#92;&quot;clear&#92;&quot;,&#92;&quot;resetOnSubmit&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;splitLayout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5ba5d8bff1a77bea&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;43e79bb77d718c95&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;342f3ee215d32fdc&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:0,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:910,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5ba5d8bff1a77bea&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;342f3ee215d32fdc&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store income&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;let income = global.get(&#39;income&#39;) || [];&#92;&#92;n&#92;&#92;nincome.push({&#92;&#92;n    ...msg.payload,&#92;&#92;n    type:&#92;&#92;&#92;&quot;income&#92;&#92;&#92;&quot;,&#92;&#92;n});&#92;&#92;n&#92;&#92;nglobal.set(&#39;income&#39;, income);&#92;&#92;n&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Thank you for submitting income!&#92;&#92;&#92;&quot;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:650,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;43e79bb77d718c95&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;961528943e1bb698&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Income Submission Form&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;d954d73f9dcd1472&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;d954d73f9dcd1472&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;New Income&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/new-Icome&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;bank-transfer-in&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;aeeec3fc1077eb1c&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;aeeec3fc1077eb1c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#1a1a1a&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;4afb4814be56a9a8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;New Expense page&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e82b719d899cbf73&#92;&quot;,&#92;&quot;3457848652ad75e1&#92;&quot;,&#92;&quot;bd90a9ad612408d3&#92;&quot;],&#92;&quot;x&#92;&quot;:1054,&#92;&quot;y&#92;&quot;:279,&#92;&quot;w&#92;&quot;:752,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;e82b719d899cbf73&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-form&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4afb4814be56a9a8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Expense Submission Form&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;854706651cd8a8f2&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Date&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Description&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;description&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Category&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;category&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Amount&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;amount&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;number&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Note&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;note&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;required&#92;&quot;:false,&#92;&quot;rows&#92;&quot;:null}],&#92;&quot;formValue&#92;&quot;:{&#92;&quot;date&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;description&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;amount&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;note&#92;&quot;:&#92;&quot;&#92;&quot;},&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;submit&#92;&quot;:&#92;&quot;submit&#92;&quot;,&#92;&quot;cancel&#92;&quot;:&#92;&quot;clear&#92;&quot;,&#92;&quot;resetOnSubmit&#92;&quot;:true,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;splitLayout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1190,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bd90a9ad612408d3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3457848652ad75e1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4afb4814be56a9a8&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:0,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1690,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bd90a9ad612408d3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4afb4814be56a9a8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store expense&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;let expense = global.get(&#39;expense&#39;) || [];&#92;&#92;n&#92;&#92;nexpense.push({&#92;&#92;n    ...msg.payload,&#92;&#92;n    type: &#92;&#92;&#92;&quot;expense&#92;&#92;&#92;&quot;,&#92;&#92;n});&#92;&#92;n&#92;&#92;nglobal.set(&#39;expense&#39;, expense);&#92;&#92;n&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Thank you for submitting expense!&#92;&#92;&#92;&quot;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1420,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3457848652ad75e1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;854706651cd8a8f2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Expense Submission Form&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;97bf3e87f4bdddc1&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;97bf3e87f4bdddc1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;New Expense&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/new-expense&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;bank-transfer-out&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;aeeec3fc1077eb1c&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;77217e256ef75328&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Your icome and expense table&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;452d561bf79727cb&#92;&quot;,&#92;&quot;0c64567c81dd6a8d&#92;&quot;],&#92;&quot;x&#92;&quot;:274,&#92;&quot;y&#92;&quot;:399,&#92;&quot;w&#92;&quot;:572,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;452d561bf79727cb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-table&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;77217e256ef75328&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;e848a5e48a6549c9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;maxrows&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;autocols&#92;&quot;:true,&#92;&quot;selectionType&#92;&quot;:&#92;&quot;click&#92;&quot;,&#92;&quot;columns&#92;&quot;:[],&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c64567c81dd6a8d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;77217e256ef75328&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Merge income and expense data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[    $globalContext(&#92;&#92;&#92;&quot;income&#92;&#92;&#92;&quot;),&#92;&#92;t   $globalContext(&#92;&#92;&#92;&quot;expense&#92;&#92;&#92;&quot;)&#92;&#92;t]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;452d561bf79727cb&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e848a5e48a6549c9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Your Income and Expense&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;7abf0b3cb6f38ca3&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;7abf0b3cb6f38ca3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Your Income and expense&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/your-icome-expense&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;calendar-multiple-check&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;aeeec3fc1077eb1c&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;1b78769d6d27d102&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event lister&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;9ce6db04b2c9d7b2&#92;&quot;],&#92;&quot;x&#92;&quot;:74,&#92;&quot;y&#92;&quot;:479,&#92;&quot;w&#92;&quot;:152,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;9ce6db04b2c9d7b2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1b78769d6d27d102&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0c64567c81dd6a8d&#92;&quot;,&#92;&quot;2ca552c7e56b3619&#92;&quot;,&#92;&quot;a7360e4a62bfc518&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Overview chart&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;424b35900722e740&#92;&quot;,&#92;&quot;058a77a65653d3f8&#92;&quot;,&#92;&quot;7246228e57ac1fc5&#92;&quot;,&#92;&quot;2ca552c7e56b3619&#92;&quot;,&#92;&quot;23a4a7d15b44876b&#92;&quot;,&#92;&quot;a7360e4a62bfc518&#92;&quot;,&#92;&quot;fe308581b8a5b9f1&#92;&quot;],&#92;&quot;x&#92;&quot;:274,&#92;&quot;y&#92;&quot;:519,&#92;&quot;w&#92;&quot;:1392,&#92;&quot;h&#92;&quot;:142},{&#92;&quot;id&#92;&quot;:&#92;&quot;424b35900722e740&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;54eca83feb7c1479&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Overview Chart&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;chartType&#92;&quot;:&#92;&quot;bar&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;property&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;category&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;replace&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:false,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1eb33c&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#5f2ed1&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1560,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;058a77a65653d3f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Calculate total&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;reduce&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:true,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;$A+payload.amount&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;$A&#92;&quot;,&#92;&quot;x&#92;&quot;:1000,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fe308581b8a5b9f1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7246228e57ac1fc5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;23a4a7d15b44876b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ca552c7e56b3619&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retrieve income&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;income&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;global&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;income&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7246228e57ac1fc5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;23a4a7d15b44876b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Convert amount to number&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.amount&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$number(payload.amount)&#92;&#92;t&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:760,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;058a77a65653d3f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a7360e4a62bfc518&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retrieve income&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;expense&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;global&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;expense&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:380,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7246228e57ac1fc5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fe308581b8a5b9f1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;7ac3890dfa74703b&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;32502807f24f79b8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Combine two object into one array&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;custom&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;array&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:false,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;424b35900722e740&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;54eca83feb7c1479&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Overview&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;47bde79e946933d2&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;47bde79e946933d2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Overview&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/overview&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;google-analytics&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;notebook&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;aeeec3fc1077eb1c&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;a0a85a5f4c29af50&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;ui-table&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;icon&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow180.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-180&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;Deploy the flow by clicking the top right &lt;strong&gt;Deploy&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Locate the *&lt;strong&gt;Open Dashboard&lt;/strong&gt; button at the top-right corner of the Dashboard 2.0 sidebar and click on it to navigate to the dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that we&#39;ve built an income-expense tracker application and gained a basic understanding of Dashboard 2.0 widgets for building dashboards.&lt;/p&gt;
&lt;h3 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/exploring-node-red-dashboard-2-widgets/#up-next&quot;&gt;Up next&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to enhance this simple application by adding more features or want to make the application personalize for users, consider the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;Webinar&lt;/a&gt; - This webinar provides an in-depth discussion of the Personalised Multi-User Dashboards feature and offers guidance on how to get started with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/&quot;&gt;Comprehensive guide: Node-RED Dashboard 2.0 layout, sidebar, and styling&lt;/a&gt; - This comprehensive guide will cover everything about Node-RED Dashboard 2.0 styling, layouts and sidebars.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/&quot;&gt;Displaying logged-in users on Dashboard 2.0&lt;/a&gt; - This detailed guide demonstrates how to display logged-in users on Dashboard 2.0 which using the FlowFuse Multiuser addon and FlowFuse.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/&quot;&gt;How to Build an Admin Dashboard with Node-RED Dashboard 2.0&lt;/a&gt; - This detailed guide demonstrates how to build a secure admin page in Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/&quot;&gt;How to Build An Application With Node-RED Dashboard 2.0&lt;/a&gt; - This guide, covers how you can build personalize multiuser dashboard using flow fuse multi-user addon.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blueprints/flowfuse-dashboard/multi-user-dashboard/&quot;&gt;Multi-User Dashboard for Ticket/Task Management blueprint&lt;/a&gt; -  this blueprint allows you to utilize templates to develop a personalized multi-user dashboard quickly. This Task management blueprint has all features such as adding, updating, and deleting tasks, user profiles, and admin dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/</id>
        <title>Why you need a low-code platform</title>
        <summary>Empowering Domain Experts with Low-Code Platforms: A Path to Seamless Digital Transformation</summary>
        <updated>2024-05-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Digital transformation is a series of technological advancements that aim to simplify complex tasks. From calculators and graphical user interfaces (GUIs) to new programming languages, these advancements have enabled individuals to create value that was once beyond their reach. The key is to understand that these tools are not meant to replace expertise but to enhance it, making complex tasks more manageable, speeding up development time, and empowering more people.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-mean-to-empower-someone%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#what-does-it-mean-to-empower-someone%3F&quot;&gt;What Does It Mean to Empower Someone?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Often, people perceive &amp;quot;empowerment&amp;quot; as a derogatory term, but it shouldn&#39;t be. Empowerment should mean enabling a domain expert to further grow their expertise. They are adding one more tool (and hopefully replacing some) to their toolbox to bring value to what they &lt;strong&gt;know&lt;/strong&gt;. And what they know is often hard to explain. It has taken years to master their role, which people usually take for granted because they don&#39;t understand the complex dance they do to make their section of the world operate flawlessly.&lt;/p&gt;
&lt;h2 id=&quot;what-do-they-do%2C-and-why-is-it-hard-to-explain%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#what-do-they-do%2C-and-why-is-it-hard-to-explain%3F&quot;&gt;What Do They Do, and Why Is It Hard to Explain?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Imagine a simple project like building a tire swing. The humorous illustration below shows how different interpretations and outcomes can arise throughout a project lifecycle:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Example of communication issues between the developers and end-users&quot; alt=&quot;Tire Swing Analogy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tire-swing-project-management-flowfuse-node-red.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This analogy highlights the potential misunderstandings and miscommunications that occur between various stakeholders in a project. From the initial customer explanation to the final product, each stage can introduce variations that stray from the original intent. This leads to a final outcome that often doesn&#39;t meet the customer&#39;s needs or expectations.&lt;/p&gt;
&lt;p&gt;In a perfect world, with clear instructions and years of prep work to define the problem statement, there&#39;s a chance the project will be completed close to 95% of what the domain expert wanted, if you&#39;re lucky. But how do you close the last 5%? Developers might move on to new projects, or worse, leave the company. The remaining tasks become difficult to complete and often go undone.&lt;/p&gt;
&lt;h2 id=&quot;put-the-domain-expert-in-the-driver%E2%80%99s-seat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#put-the-domain-expert-in-the-driver%E2%80%99s-seat&quot;&gt;Put the Domain Expert in the Driver’s Seat&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Calculators were not created to be used only by mathematicians. GUIs weren&#39;t created to be used only by programmers. They were created to make people&#39;s lives easier. No longer was there a &lt;strong&gt;need&lt;/strong&gt; to use the command line to start an application; simply click the icon for the desired application. These simple iterations open the opportunity for a larger range of people to leverage tools.&lt;/p&gt;
&lt;p&gt;With low-code applications, the process is the same. Put the domain expert in the driver’s seat. Make them their own developer. They understand the process better than anyone else. Pair them with a low-code domain expert and have them co-develop the application.&lt;/p&gt;
&lt;p&gt;With the domain expert in the driver’s seat of their own low-code project, the days of the last 5% undone become less common. There is always a path forward.&lt;/p&gt;
&lt;h2 id=&quot;which-low-code-solution-should-you-go-with%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#which-low-code-solution-should-you-go-with%3F&quot;&gt;Which Low-Code Solution Should You Go With?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With over 10 years of development emerging from &lt;a href=&quot;https://flowfuse.com/blog/2024/02/history-of-nodered/&quot;&gt;IBM’s Emerging Technology Group&lt;/a&gt;, Node-RED is a clear leader.  Dare I say the de facto solution. It is open-source and easy to spin up. It is currently being leveraged in many industries; ranging from pharmaceuticals, to agriculture, and to telecom.&lt;/p&gt;
&lt;p&gt;But you might think Node-RED is just a proof-of-concept tool. You’re wrong. Has it been used as &lt;a href=&quot;https://www.cloudflare.com/learning/access-management/what-is-shadow-it/&quot;&gt;Shadow-IT&lt;/a&gt;? Yes, and that is beautiful and awesome. Innovation is at the heart of Shadow-IT. No one ever said, “There is a tool supported by my IT company that would be perfect for the job, but I think I would rather deploy an unsanctioned tool.” The flaw in this statement is believing there is a choice in tools. Node-RED has often been the only tool available in the domain expert&#39;s toolbox.&lt;/p&gt;
&lt;h2 id=&quot;increased-development-speed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#increased-development-speed&quot;&gt;Increased Development Speed&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Domain experts often find themselves needing to develop solutions but learning a new programming language can be time-consuming. With the open-source community behind Node-RED, many common integrations and transformations have already been created. This community sharing of knowledge accelerates development because often a needed programming task has already been developed and shared. This allows domain experts to repurpose existing code as &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;&lt;strong&gt;nodes, flows, or collections&lt;/strong&gt;&lt;/a&gt;, significantly speeding up the development process.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#flowfuse&quot;&gt;FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is your solution to solving Shadow-IT and paving the way for your &lt;a href=&quot;https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/&quot;&gt;Citizen Development&lt;/a&gt; journey. All the reasons why Node-RED hasn’t been sanctioned within organizations have nothing to do with its ability to execute but more with its lack of scalability, easy-to-use security, and manageability. Enter FlowFuse, developed by the same people who developed your go-to low-code solution. FlowFuse addresses exactly the problems that put it in the Shadow-IT realm.&lt;/p&gt;
&lt;p&gt;With security and scalability top of mind, FlowFuse allows IT teams to manage their Node-RED deployments with features like Role-Based Access Control (RBAC), remote management of Node-RED runtimes, and backup and recovery of Node-RED deployments called Snapshots. These are just a few of the features that elevate an already widely used solution, making it ready for enterprise networks.&lt;/p&gt;
&lt;h3 id=&quot;low-code-platform-success-in-the-real-world&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#low-code-platform-success-in-the-real-world&quot;&gt;Low-code platform success in the real world&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Low-code platforms are industry-agnostic, with applications varying from industrial manufacturing to news agencies. Here are some customer success stories of how the FlowFuse low-code platform has helped:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/customer-stories/leveraging-node-red-and-flowfuse-to-automate-precision-manufacturing/&quot;&gt;&lt;strong&gt;Abrasive Technology:&lt;/strong&gt;&lt;/a&gt; Leveraged Node-RED and FlowFuse to optimize automation and improve operational efficiency. The transition to FlowFuse Cloud has enhanced their ability to manage Node-RED instances effectively, supporting innovation and agility in their manufacturing processes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/customer-stories/node-red-building-management/&quot;&gt;&lt;strong&gt;Power Workplace:&lt;/strong&gt;&lt;/a&gt; Utilized FlowFuse and Node-RED to automate building management, significantly reducing development time and enhancing scalability and reliability. This has helped them meet security and compliance requirements more easily, improving service delivery across multiple regions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/customer-stories/manufacturing-digital-transformation/&quot;&gt;&lt;strong&gt;Large US Manufacturing Company:&lt;/strong&gt;&lt;/a&gt; Employed Node-RED and FlowFuse to drive digital transformation across numerous manufacturing sites. By decentralizing innovation, they have improved data visibility, real-time decision-making, and overall process efficiency, using FlowFuse to manage extensive Node-RED deployments and version control.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-low-code-future&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/why-you-need-a-low-code-platform/#the-low-code-future&quot;&gt;The Low-Code Future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, low-code platforms like Node-RED and FlowFuse empower domain experts to take control of their own digital transformation journeys. By putting the domain expert in the driver’s seat, low-code applications enable them to create solutions tailored to their specific needs and requirements. This approach not only reduces the risk of the last 5% of a project going undone but also fosters a culture of innovation and collaboration within organizations.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/product-strategy-updates/</id>
        <title>Product Mission Statement and Strategy Updates</title>
        <summary>We&#39;ve recently refined our product strategy to better align with our mission and vision. Here&#39;s a summary of the changes.</summary>
        <updated>2024-05-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/product-strategy-updates/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It&#39;s now been two years since our first ever &lt;code&gt;0.1.0&lt;/code&gt; release of FlowFuse. In that time, we&#39;ve been working hard to build out a platform to help users elevate their Node-RED experience. In that time we&#39;ve delivered some incredibly valuable features to FlowFuse users such as centralized instance management, remote deployments and version control. We&#39;ve also learned a lot about our users, their needs, and how we can best serve them, and in a recent reflection on our product strategy decided to refine our product mission statement.&lt;/p&gt;
&lt;h2 id=&quot;product-mission-statement&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#product-mission-statement&quot;&gt;Product Mission Statement&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is used across a range of industries and use-cases, and in the hundreds of conversations we&#39;ve had with customers, we&#39;ve found that in every scenario there is a common pattern. So, to reflect ths, we&#39;ve created a new Product Mission Statement, to make it clear to existing and prospective users of FlowFuse what it is that we&#39;re striving for.&lt;/p&gt;
&lt;p&gt;Our new mission statement is as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Provide the best way to build, manage and deploy Node-RED applications at scale, in reliable and secure production environments.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We believe that by focusing on this mission, we can better serve our users and provide them with the tools they need to succeed. This mission statement will act as the north star for our product prioritization moving forward, and be our compass to ensure we&#39;re staying on track in delivering value to our users.&lt;/p&gt;
&lt;h3 id=&quot;build&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#build&quot;&gt;Build&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse strives to be the best place to build Node-RED applications by providing tools to help users build applications with more confidence.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simplified Hosting:&lt;/strong&gt; Whether you want cloud-hosted instances, or to run Node-RED on edge devices, FlowFuse provides the smoothest experience to setup new Node-RED instances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trust&lt;/strong&gt;: &lt;a href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/&quot;&gt;Certified Nodes&lt;/a&gt; ensure Node-RED developers can trust the reliability, quality and security of third-party nodes they&#39;re using in their applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Control&lt;/strong&gt;: &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/&quot;&gt;Snapshots&lt;/a&gt; capture point-in-time views of Node-RED flows, environment variables and other configuration settings. We even capture automatic snapshots of your flows every time you deploy, so you can always be confident you have a backup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaborative Development&lt;/strong&gt;: We are building FlowFuse to be a platform that enables teams to work seamlessly together on Node-RED applications. From the &lt;a href=&quot;https://flowfuse.com/docs/user/shared-library/&quot;&gt;Team Library&lt;/a&gt;, through to &lt;a href=&quot;https://flowfuse.com/blog/2024/04/node-red-multiplayer/&quot;&gt;Node-RED Multiplayer&lt;/a&gt;, we want to make sure that FlowFuse is the best platform for collaborative development in Node-RED.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote Access:&lt;/strong&gt; FlowFuse provides a secure way to access your Node-RED instances and devices from anywhere in the world, so you can build and debug your applications with ease.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;manage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#manage&quot;&gt;Manage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With FlowFuse, it&#39;s possible to manage thousands of Node-RED instances, all in one place. We make sure you have a clear picture of what&#39;s happening across all of your instances, and provide tools to help you manage them effectively.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized Management&lt;/strong&gt;: FlowFuse provides a single entry point to manage all of your Node-RED instances, no matter where they are hosted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: FlowFuse provides a range of security features to help you keep your Node-RED instances secure. From &lt;a href=&quot;https://flowfuse.com/docs/user/user-settings/#two-factor-authentication&quot;&gt;Two-Factor Authentication&lt;/a&gt; to &lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;Role-Based Access Control&lt;/a&gt;, we&#39;re building FlowFuse to be the most secure way to manage your Node-RED instances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frictionless Maintenance:&lt;/strong&gt; Whether you&#39;re updating your Node-RED version, or one of the many third-party dependencies that your applications depend upon, FlowFuse provides tools to make it easy to keep your instances up-to-date and running smoothly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability:&lt;/strong&gt; FlowFuse provides tools to help you keep an eye on your Node-RED instances and make sure they&#39;re running smoothly. Get alerts when something goes wrong, and use the &lt;a href=&quot;https://flowfuse.com/docs/user/logs/#audit-log&quot;&gt;Audit Logs&lt;/a&gt; to help you debug issues when they arise.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deploy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#deploy&quot;&gt;Deploy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With FlowFuse, we aim to provide the best way to deploy Node-RED applications to production environments, whether that be to hundreds of remote devices, or via staging environments to ensure you can deploy with confidence.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DevOps:&lt;/strong&gt; Test your applications in development and staging environments, ensuring you can deploy them with confidence to production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote Deployments:&lt;/strong&gt; Deploy your applications to hundreds of remote devices with a single-click, ensuring you can get your applications running in production quickly and easily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability:&lt;/strong&gt; FlowFuse users can have trust that their applications will run without issues with features like &lt;a href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/&quot;&gt;High Availability&lt;/a&gt;. FlowFuse makes sure users have the tools to monitor and manage the reliability of their applications, including being alerted when things go wrong, and making the recovery as easy as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our development team are busy working on a range of new features to help us deliver on our mission. If you&#39;re interested to see what highlight features we&#39;re working on for the next release (v2.5) in four weeks time, you can checkout our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/1/views/39&quot;&gt;Development Board&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;p&gt;For longer term planning, we have our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/3/views/9&quot;&gt;Product Planning Board&lt;/a&gt;, which outlines the features we&#39;re working on for the next 12 months. It&#39;s subject to change, as we&#39;re always &lt;a href=&quot;https://flowfuse.com/handbook/company/values/#%F0%9F%94%81-iterative-improvement&quot;&gt;iterating&lt;/a&gt;, but it gives a good idea of where our focus will likely be in the coming months.&lt;/p&gt;
&lt;p&gt;In the mean time, please do reach out if there are any features you&#39;d like to see in FlowFuse, or if you have any feedback on our product strategy. We&#39;re always keen to hear from our users and learn how we can better serve you.&lt;/p&gt;
&lt;h3 id=&quot;read-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/product-strategy-updates/#read-more&quot;&gt;Read More&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re interested in learning more about our company and product strategies, you can read more detail in our Handbook:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/company/strategy/&quot;&gt;Company Strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/engineering/product/strategy/&quot;&gt;Product Mission Statement&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/</id>
        <title>The MIND stack with Node-RED and FlowFuse Dashboard 2.0</title>
        <summary>Leveraging FlowFuse for a Lighter MIND Stack (MIND = MQTT, InfluxDB, Node-RED, Dashboard 2.0)</summary>
        <updated>2024-05-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/"/>
        <author><name></name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The &lt;a href=&quot;https://flowfuse.com/blog/2023/02/ming-blog/&quot;&gt;MING stack&lt;/a&gt; has gained significant popularity over the years as it built upon open-source projects.  That has given way to many people leveraging this stack to build solutions upon in various different environments.  The MING stack is composed of 4 main components, &lt;a href=&quot;https://mosquitto.org/&quot;&gt;MQTT&lt;/a&gt;, &lt;a href=&quot;https://www.influxdata.com/&quot;&gt;InfluxDB&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt;, and &lt;a href=&quot;https://grafana.com/&quot;&gt;Grafana&lt;/a&gt;.  Combined together are the 4 main pillars, data transportation, data storage, data transformation, and visualizations.  With this, it requires the management of 4 different applications, which often reside on the same server, but not necessarily.  With more moving parts, creates complexity.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-integrated-iot-deployment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#flowfuse%3A-integrated-iot-deployment&quot;&gt;FlowFuse: Integrated IoT Deployment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With FlowFuse we have bundled up 3 of those 4.  First and foremost, the FlowFuse platform deploys Node-RED in two main ways.  A cloud based deployment and remote deployment with management from the FlowFuse platform.  Part of this management piece leverage MQTT between the devices for management.  Because of this we have a built in MQTT broker that allows for communication between Node-RED instance within the FlowFuse platform.  Lastly, with the release of Dashboards 2.0 from FlowFuse we have introduced the next generation of visualizations for the Node-RED platform.&lt;/p&gt;
&lt;p&gt;It often makes sense to deploy a full MING stack, but in some deployments, it might be necessary to deploy a more simplistic version of the MING stack.  This is where MIND comes into play.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-mqtt%3A-simplified-communications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#flowfuse-mqtt%3A-simplified-communications&quot;&gt;FlowFuse MQTT: Simplified Communications&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse has a built-in feature called &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;project link nodes&lt;/a&gt;, which leverages MQTT, that allows the communication of data between FlowFuse runtimes of Node-RED. One caveat is that this MQTT broker is only available within the FlowFuse platform. What this means is there needs to be some form of translation to be done within Node-RED.  This isn’t a big deal for small deployments, because often Node-RED runtimes at the edger are collecting data from various sources that aren’t MQTT. The flow of data is as follows:&lt;/p&gt;
&lt;p&gt;Sensor &amp;gt; Node-RED(&lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;FlowFuse Device Agent&lt;/a&gt;) &amp;gt; &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;MQTT Encapsulated by FlowFuse&lt;/a&gt; &amp;gt; Node-RED(FlowFuse Platform) &amp;gt; InfluxDB&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;&amp;quot;Screenshot showing the flow of data: Sensor &gt; Node-RED(FlowFuse Device Agent) &gt; MQTT Encapsulated by FlowFuse &gt; Node-RED(FlowFuse Platform) &gt; InfluxDB&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sensor-data-mqtt-node-red-dashboard-influxdb.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;A key benefit of having the MQTT broker encapsulated by FlowFuse is that it becomes extremely easy to set up. With the project nodes, there isn’t a need to configure certificates or security credentials because it is only exposed internally to the FlowFuse platform. Furthermore, the access and control limits are applied by the platform so your data remains within the same FlowFuse Team.&lt;/p&gt;
&lt;h3 id=&quot;influxdb%3A-efficient-data-storage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#influxdb%3A-efficient-data-storage&quot;&gt;InfluxDB: Efficient Data Storage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The deployment of InFluxDB doesn&#39;t change in the MIND configuration.  The only significant change is that InFluxDB is deployed higher up in the architecture and closer to the FlowFuse Platform instead of the edge.&lt;/p&gt;
&lt;h3 id=&quot;data-visualization-with-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#data-visualization-with-dashboard-2.0&quot;&gt;Data Visualization with Dashboard 2.0&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse&#39;s Dashboard 2.0 makes it incredibly easy to visualize your data.  You can create beautiful and informative dashboards in minutes. Simply drag and drop your desired widgets onto the canvas, and configure them with a few clicks.&lt;/p&gt;
&lt;p&gt;We have gone through the step of providing you with an example dashboard for visualizing your MIND stack.&lt;/p&gt;
&lt;div id=&quot;nr-flow-182&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow182 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;MIND&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1423665d39048eba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;flowfuse/temp&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;auto-detect&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;e8ea838e83035408&#92;&quot;,&#92;&quot;nl&#92;&quot;:false,&#92;&quot;rap&#92;&quot;:true,&#92;&quot;rh&#92;&quot;:0,&#92;&quot;inputs&#92;&quot;:0,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7ddcaadd5c43f11d&#92;&quot;,&#92;&quot;c359b55bc77165c2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;993651c073e7659c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;flowfuse/RH&#92;&quot;,&#92;&quot;qos&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;auto-detect&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;e8ea838e83035408&#92;&quot;,&#92;&quot;nl&#92;&quot;:false,&#92;&quot;rap&#92;&quot;:true,&#92;&quot;rh&#92;&quot;:0,&#92;&quot;inputs&#92;&quot;:0,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;01f4e507e7deaaea&#92;&quot;,&#92;&quot;33e5c2e4a61d01e3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7ddcaadd5c43f11d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temp&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;temp&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f39435df2b4db94f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;01f4e507e7deaaea&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f39435df2b4db94f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f39435df2b4db94f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;custom&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:false,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;reduceExp&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInit&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceInitType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceFixup&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fa067011fa3f705f&#92;&quot;,&#92;&quot;c9d37220d787ac92&#92;&quot;,&#92;&quot;681b2e5009ec5e1e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa067011fa3f705f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send it to InfluxDB&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var temp = Number(msg.payload.temp);&#92;&#92;nvar RH = Number(msg.payload.RH);&#92;&#92;n&#92;&#92;nmsg.measurement = &#92;&#92;&#92;&quot;room1&#92;&#92;&#92;&quot;;&#92;&#92;nmsg.payload = {Temperature:temp,RH:RH};&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:770,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0e86e1bd4bf8b9f6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e86e1bd4bf8b9f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;influxdb out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;influxdb&#92;&quot;:&#92;&quot;cb09abcd8b693ca8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;measurement&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;precision&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retentionPolicy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;database&#92;&quot;:&#92;&quot;database&#92;&quot;,&#92;&quot;precisionV18FluxV20&#92;&quot;:&#92;&quot;ms&#92;&quot;,&#92;&quot;retentionPolicyV18Flux&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;org&#92;&quot;:&#92;&quot;organization&#92;&quot;,&#92;&quot;bucket&#92;&quot;:&#92;&quot;bucket&#92;&quot;,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c359b55bc77165c2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;11df00492fb20acd&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Verdana,Verdana,Geneva,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;33e5c2e4a61d01e3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;11df00492fb20acd&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Verdana,Verdana,Geneva,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:510,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c9d37220d787ac92&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temp&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var temp = Number(msg.payload.temp);&#92;&#92;n&#92;&#92;nmsg.payload = temp;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;432850955a867e1e&#92;&quot;,&#92;&quot;28d0b846fd2a48ab&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;681b2e5009ec5e1e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var RH = Number(msg.payload.RH);&#92;&#92;nmsg.payload = RH;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a41e65a351476137&#92;&quot;,&#92;&quot;80b1312f88e4f656&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;432850955a867e1e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;aa70ec0abc058d78&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Live Temperature &#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;8&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:950,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a41e65a351476137&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;aa70ec0abc058d78&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Live RH&#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;8&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;87ebfee665b784ee&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT min(Temperature) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7d727f5a7723a73d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7d727f5a7723a73d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;influxdb in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;influxdb&#92;&quot;:&#92;&quot;cb09abcd8b693ca8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Temp&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rawOutput&#92;&quot;:false,&#92;&quot;precision&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retentionPolicy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;org&#92;&quot;:&#92;&quot;organization&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fe9230e31884d82b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1da5df166734acac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temp&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:3,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;87ebfee665b784ee&#92;&quot;],[&#92;&quot;1322af95dd29b8c3&#92;&quot;],[&#92;&quot;717e1a07222ec348&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1322af95dd29b8c3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT max(Temperature) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7d727f5a7723a73d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;88e2e00b4e5f5fd6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-dropdown&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Select Option:&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;multiple&#92;&quot;:false,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;label&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;label&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1da5df166734acac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;57a7757bf943bce5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Temp Stats&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Verdana,Verdana,Geneva,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1290,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cac36785f12f3bf5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var min = msg.payload[0].min&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Minimum is &#92;&#92;&#92;&quot; + min;&#92;&#92;nreturn (msg)&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;57a7757bf943bce5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fc6330b5fcc33acc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var avg = msg.payload[0].max;&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Max is &#92;&#92;&#92;&quot; + avg;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;57a7757bf943bce5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6453914fa7bdd751&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temp&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload[0]&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;min&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;max&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;count&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:3,&#92;&quot;x&#92;&quot;:950,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cac36785f12f3bf5&#92;&quot;],[&#92;&quot;fc6330b5fcc33acc&#92;&quot;],[&#92;&quot;d29294d236bef25c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;717e1a07222ec348&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Count&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT count(Temperature) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7d727f5a7723a73d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d29294d236bef25c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Count&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var count = msg.payload[0].count;&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Total Record is &#92;&#92;&#92;&quot; + count;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;57a7757bf943bce5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7465ddb4fd72e6a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT min(RH) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;db0873d1bbef089a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;db0873d1bbef089a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;influxdb in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;influxdb&#92;&quot;:&#92;&quot;cb09abcd8b693ca8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read RH&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rawOutput&#92;&quot;:false,&#92;&quot;precision&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retentionPolicy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;org&#92;&quot;:&#92;&quot;organization&#92;&quot;,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f14e43cc318fa92b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a27e50703cb15e38&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:3,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e7465ddb4fd72e6a&#92;&quot;],[&#92;&quot;0e8acb8b65e368f6&#92;&quot;],[&#92;&quot;7402a7eec1245643&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0e8acb8b65e368f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT max(RH) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;db0873d1bbef089a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a36dafb79f2fce75&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-dropdown&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Select Option:&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;multiple&#92;&quot;:false,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;label&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;label&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;Total&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a27e50703cb15e38&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4800381c4950d245&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;RH Stats&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:true,&#92;&quot;font&#92;&quot;:&#92;&quot;Verdana,Verdana,Geneva,sans-serif&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1280,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4af1d2b0abf0009f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Min&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var min = msg.payload[0].min&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Minimum is &#92;&#92;&#92;&quot; + min;&#92;&#92;nreturn (msg)&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:620,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4800381c4950d245&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cfc4f16f835d3724&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Max&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var avg = msg.payload[0].max;&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Max is &#92;&#92;&#92;&quot; + avg;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4800381c4950d245&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49ac1cdfe4289eac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;RH&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload[0]&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;min&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;max&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;hask&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;count&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:3,&#92;&quot;x&#92;&quot;:950,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4af1d2b0abf0009f&#92;&quot;],[&#92;&quot;cfc4f16f835d3724&#92;&quot;],[&#92;&quot;57b2d15bae6a4d42&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7402a7eec1245643&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Count&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT count(RH) FROM room1`;&#92;&#92;n&#92;&#92;n// Pass the modified message object to the next node&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;db0873d1bbef089a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;57b2d15bae6a4d42&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Count&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var count = msg.payload[0].count;&#92;&#92;nmsg.payload = &#92;&#92;&#92;&quot;Total Record is &#92;&#92;&#92;&quot; + count;&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1090,&#92;&quot;y&#92;&quot;:700,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4800381c4950d245&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb1cbe8ec45b5de7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Operation&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:100,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;931c16333d3efcad&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Operation&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f200e4be2158481e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Operation&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;80b1312f88e4f656&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Live RH&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-34&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;rounded&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Live RH&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;%&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;40&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;70&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;28d0b846fd2a48ab&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Live Temperature&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-34&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;rounded&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;Degrees C&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;40&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:950,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f22ff292ec2d0964&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-form&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Start Time&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;11df00492fb20acd&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Select Date and Time&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;options&#92;&quot;:[{&#92;&quot;label&#92;&quot;:&#92;&quot;Start&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;Start Date&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Start Time&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;Start Time&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Stop Date&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;Stop Date&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null},{&#92;&quot;label&#92;&quot;:&#92;&quot;Stop Time&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;Stop Time&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;required&#92;&quot;:true,&#92;&quot;rows&#92;&quot;:null}],&#92;&quot;formValue&#92;&quot;:{&#92;&quot;Start Date&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;Start Time&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;Stop Date&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;Stop Time&#92;&quot;:&#92;&quot;&#92;&quot;},&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;submit&#92;&quot;:&#92;&quot;submit&#92;&quot;,&#92;&quot;cancel&#92;&quot;:&#92;&quot;clear&#92;&quot;,&#92;&quot;resetOnSubmit&#92;&quot;:false,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;splitLayout&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;05dfd0f5d8b97fba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;05dfd0f5d8b97fba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;start date and end date&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var startDate = msg.payload[&#92;&#92;&#92;&quot;Start Date&#92;&#92;&#92;&quot;];&#92;&#92;nvar startTime = msg.payload[&#92;&#92;&#92;&quot;Start Time&#92;&#92;&#92;&quot;];&#92;&#92;nvar stopDate = msg.payload[&#92;&#92;&#92;&quot;Stop Date&#92;&#92;&#92;&quot;];&#92;&#92;nvar stopTime = msg.payload[&#92;&#92;&#92;&quot;Stop Time&#92;&#92;&#92;&quot;];&#92;&#92;n&#92;&#92;n&#92;&#92;n&#92;&#92;nvar startTimestamp = `${startDate}T${startTime}:00+05:30`; // +05:30 is the offset for IST&#92;&#92;nvar stopTimestamp = `${stopDate}T${stopTime}:00+05:30`; // +05:30 is the offset for IST&#92;&#92;n&#92;&#92;n// Construct the query using the provided start and stop timestamps&#92;&#92;nmsg.query = `SELECT * FROM room1 WHERE time &amp;gt;= &#39;${startTimestamp}&#39; AND time &amp;lt;= &#39;${stopTimestamp}&#39;`;&#92;&#92;n&#92;&#92;nreturn msg;&#92;&#92;n&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:0,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a1d3dda63ad3bd6f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a1d3dda63ad3bd6f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;influxdb in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;influxdb&#92;&quot;:&#92;&quot;cb09abcd8b693ca8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read&#92;&quot;,&#92;&quot;query&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rawOutput&#92;&quot;:false,&#92;&quot;precision&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;retentionPolicy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;org&#92;&quot;:&#92;&quot;organization&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad4f278b680749b2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;024b2830c4183fd1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;function&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Table&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;var temp=[];&#92;&#92;nvar a = msg.payload;&#92;&#92;n&#92;&#92;na.forEach(function (value,index) {&#92;&#92;ntemp.push(value)&#92;&#92;n});&#92;&#92;n&#92;&#92;nmsg.payload=temp&#92;&#92;n&#92;&#92;nreturn msg;&#92;&quot;,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;noerr&#92;&quot;:0,&#92;&quot;initialize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;finalize&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;libs&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1650,&#92;&quot;y&#92;&quot;:780,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5bb2164a578330bd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-table&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;11df00492fb20acd&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Historic Data&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;text&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;maxrows&#92;&quot;:0,&#92;&quot;autocols&#92;&quot;:true,&#92;&quot;columns&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad4f278b680749b2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;copy-array&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Table&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5bb2164a578330bd&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;dd00c6e47e1480ad&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;aa70ec0abc058d78&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Clear Temp&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;432850955a867e1e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7e6d8eb54dc0d8aa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;aa70ec0abc058d78&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Clear RH&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a41e65a351476137&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fe9230e31884d82b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;copy-array&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temp Data&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6453914fa7bdd751&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f14e43cc318fa92b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;copy-array&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;dc1c7f4e5ddc86f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;RH Data&#92;&quot;,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49ac1cdfe4289eac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e8ea838e83035408&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;mqtt-broker&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;broker&#92;&quot;:&#92;&quot;192.168.1.39&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;1883&#92;&quot;,&#92;&quot;clientid&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;autoConnect&#92;&quot;:true,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;protocolVersion&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;keepalive&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cleansession&#92;&quot;:true,&#92;&quot;autoUnsubscribe&#92;&quot;:true,&#92;&quot;birthTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;birthRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;birthPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;birthMsg&#92;&quot;:{},&#92;&quot;closeTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;closeRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;closePayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;closeMsg&#92;&quot;:{},&#92;&quot;willTopic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willQos&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;willRetain&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;willPayload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;willMsg&#92;&quot;:{},&#92;&quot;userProps&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;sessionExpiry&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;cb09abcd8b693ca8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;influxdb&#92;&quot;,&#92;&quot;hostname&#92;&quot;:&#92;&quot;127.0.0.1&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;8086&#92;&quot;,&#92;&quot;protocol&#92;&quot;:&#92;&quot;http&#92;&quot;,&#92;&quot;database&#92;&quot;:&#92;&quot;environment&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usetls&#92;&quot;:false,&#92;&quot;tls&#92;&quot;:&#92;&quot;cff98b62.009678&#92;&quot;,&#92;&quot;influxdbVersion&#92;&quot;:&#92;&quot;1.x&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;http://localhost:8086&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;rejectUnauthorized&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;11df00492fb20acd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Room 1&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;6a43b6805a66d2b8&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;aa70ec0abc058d78&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Live Data&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;6a43b6805a66d2b8&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;f02746ad7e1ab68c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Stat Data&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;6a43b6805a66d2b8&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;cff98b62.009678&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tls-config&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;cert&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ca&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;certname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;keyname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;caname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;servername&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;verifyservercert&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;6a43b6805a66d2b8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Environment Data&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;20ae73d735a60fbc&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/page2&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;flex&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;074b315414230834&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;20ae73d735a60fbc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;UI Name&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;showPathInSidebar&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;074b315414230834&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Theme Name&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow182.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-182&#39;) })&lt;/script&gt;
&lt;p&gt;This dashboard example allows you to do quick visualizations of data from an InfluxDB.  In this particular case, it leverages the Relative Humidity (RH) and Temperature of a sensor.  It captures the data and stores in InfluxDB and then visualizes it in Dashboard 2.0.  Use this as a starting point to display data in the MIND stack.&lt;/p&gt;
&lt;h2 id=&quot;advantages-of-flowfuse%E2%80%99s-mind-stack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#advantages-of-flowfuse%E2%80%99s-mind-stack&quot;&gt;Advantages of FlowFuse’s MIND Stack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse provides built-in features, such as MQTT, backups, deployment pipelines, and access control, helping to protect data and devices from unauthorized access. FlowFuse simplifies the MING stack to the MIND deployment, bringing numerous benefits to organizations. It reduces the complexity of managing multiple components, minimizing configuration, update, and maintenance overhead. The single platform approach for MQTT, Node-RED, and visualization simplifies maintenance tasks, lowers the risk of conflicts, and ensures consistency. FlowFuse&#39;s lighter deployment requires fewer hardware resources, making it suitable for resource-constrained environments or cost-sensitive projects. Organizations can potentially save on licensing and maintenance costs by reducing the number of deployed software components. Faster deployment is enabled with fewer components to set up and configure, allowing projects to realize value sooner. FlowFuse&#39;s scalable architecture handles large data volumes and devices, ensuring suitability for growing IoT deployments.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While we believe that the MING stack is here to stay, we believe as the market matures, it should offer many different variations suitable for each customer&#39;s needs.  However, we find that the MIND offering does fill a niche in the market that may better suit your needs.  None the less, choosing FlowFuse to manage your Node-RED runtimes will ensure that your applications will be secure, scalable, and easily manageable.  Allowing your domain experts to take control and extend their knowledge bringing increased value to industrial facilities around the world.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/</id>
        <title>Mapping location data within Node-RED Dashboard 2.0.</title>
        <summary>Step-by-step guide to plot location data on dashboard 2.0.</summary>
        <updated>2024-05-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Fleet management in IoT uses sensors and software to collect real-time data on vehicles, such as location, fuel consumption, and driver behavior. This data allows companies to optimize routes, reduce costs, improve safety, and enhance overall operational efficiency of their fleet. Building an application that allows the tracking of location to support Fleet management is what this post is about.&lt;/p&gt;
&lt;p&gt;Before moving further, make sure you have installed Dashboard 2.0. If you are new to Dashboard 2.0, please refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard 2.0&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h2 id=&quot;installing-world-map-custom-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#installing-world-map-custom-node&quot;&gt;Installing world map custom node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To render an interactive world map webpage for plotting location data, we will use a popular custom node called &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-web-worldmap&quot;&gt;node-red-contrib-web-worldmap-page&lt;/a&gt;. This node offers extensive features enabling us to render a world map and plot various items with different icons, colors, NATO symbologies, ranges, and more.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click the Node-RED Settings (top-right).&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Manage Palette&amp;quot;.&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Install&amp;quot; tab.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;node-red-contrib-web-worldmap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;retrieving-location-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#retrieving-location-data&quot;&gt;Retrieving location Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before plotting locations, we need to obtain the data first. For this purpose, we will utilize the &lt;a href=&quot;https://tfe-opendata.readme.io/docs/getting-started&quot;&gt;Edenburg Open Public Transportation API&lt;/a&gt;. This API provides the live locations of all of Edenburg&#39;s public buses and trams, enabling us to access the necessary data for plotting on Worldmap within Dashboard 2.0.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;Inject&lt;/strong&gt; node onto the canvas and set the repeat property to a 20-second interval.&lt;/li&gt;
&lt;li&gt;Drag an HTTP request node onto the canvas, Dobule-click on it and choose &lt;strong&gt;GET&lt;/strong&gt; method, and enter &lt;code&gt;https://tfe-opendata.com/api/v1/vehicle_locations&lt;/code&gt; in the URL field and select return  as &lt;strong&gt;a parsed json object&lt;/strong&gt;. This API is public, so no need for environment variables. For private APIs, consider using &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;environment variables&lt;/a&gt; for security.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the HTTP request node configuration for retrieving data from the API&quot; alt=&quot;&amp;quot;Screenshot of the HTTP request node configuration for retrieving data from the API&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-http-request-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;Inject&lt;/strong&gt; node&#39;s output to the &lt;strong&gt;HTTP request&lt;/strong&gt; node&#39;s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;formatting-location-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#formatting-location-data&quot;&gt;Formatting Location Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To ensure compatibility with the Worldmap custom node, we need to format the location data appropriately.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the &lt;strong&gt;Change&lt;/strong&gt; node onto the canvas, and set the &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;msg.payload.vehicles&lt;/code&gt;, and give it name &lt;strong&gt;Set payload&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Change node setting the payload to the vehicles JSON array containing actual vehicle location data&quot; alt=&quot;Screenshot of the Change node setting the payload to the vehicles JSON array containing actual vehicle location data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Split&lt;/strong&gt; node onto the canvas.&lt;/li&gt;
&lt;li&gt;Add another &lt;strong&gt;Change&lt;/strong&gt; node to the canvas. Configure it to set and delete properties as shown in the image below, and give it name &lt;strong&gt;Change and delete properties&lt;/strong&gt;. By changing and deleting properties of the location, we ensure that only the properties acceptable by the &lt;strong&gt;Worldmap&lt;/strong&gt; node are included in the location data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Change node configuring properties to ensure compatibility with the Worldmap node&quot; alt=&quot;Screenshot of the Change node configuring properties to ensure compatibility with the Worldmap node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-change-node-changing-and-deleting-properties.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;Switch&lt;/strong&gt; node onto the canvas and add conditions to check if &lt;code&gt;msg.payload.vehicle_type&lt;/code&gt; is equal to &lt;strong&gt;tram&lt;/strong&gt; or not.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Switch node checking if the vehicle type is tram or not&quot; alt=&quot;Screenshot of the Switch node checking if the vehicle type is tram or not&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-switch-node-checking-is-vehicale-type-is-tram-or-not.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Add another &lt;strong&gt;Change&lt;/strong&gt; node to the canvas and give it a name &lt;strong&gt;set icon and icon color for tram&lt;/strong&gt;. Set &lt;code&gt;msg.payload.icon&lt;/code&gt; to &lt;strong&gt;fa-train&lt;/strong&gt; and &lt;code&gt;msg.payload.iconColor&lt;/code&gt; to &lt;strong&gt;yellow&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Change node setting the icon and icon color for tram&quot; alt=&quot;Screenshot of the Change node setting the icon and icon color for tram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-change-node-setting-icon-for-tram.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Add another &lt;strong&gt;Change&lt;/strong&gt; node to the canvas and give it a name &lt;strong&gt;set icon and icon color for bus&lt;/strong&gt;. Set &lt;code&gt;msg.payload.icon&lt;/code&gt; to &lt;strong&gt;bus&lt;/strong&gt; and &lt;code&gt;msg.payload.iconColor&lt;/code&gt; to &lt;strong&gt;red&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the Change node setting the icon and icon color for bus&quot; alt=&quot;Screenshot of the Change node setting the icon and icon color for bus&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-change-node-setting-icon-for-bus.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;HTTP request&lt;/strong&gt; node&#39;s output to the input of the &lt;strong&gt;Change&lt;/strong&gt; node named &lt;strong&gt;Set payload&lt;/strong&gt;, and connect the output of that &lt;strong&gt;Change&lt;/strong&gt; node to the input of the &lt;strong&gt;Split&lt;/strong&gt; node.&lt;/li&gt;
&lt;li&gt;Then, connect the output of the &lt;strong&gt;Split&lt;/strong&gt; node to the input of the &lt;strong&gt;Change&lt;/strong&gt; node named &lt;strong&gt;Change and delete properties&lt;/strong&gt;, and connect the output of the &amp;quot;Change and delete properties&amp;quot; node to the input of the &lt;strong&gt;Switch&lt;/strong&gt; node. Then &lt;strong&gt;Switch&lt;/strong&gt; node&#39;s first output to the input of the &lt;strong&gt;Change&lt;/strong&gt; node named &lt;strong&gt;set icon and icon color for tram&lt;/strong&gt;, and its second output to the input of the &lt;strong&gt;Change&lt;/strong&gt; node named &lt;strong&gt;set icon and icon color for bus&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;plotting-location-data-on-worldmap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#plotting-location-data-on-worldmap&quot;&gt;Plotting location data on Worldmap&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;Worldmap&lt;/strong&gt; node onto the canvas. Set the path to &lt;strong&gt;/worldmap&lt;/strong&gt; and keep the rest of the settings unchanged, although you can modify other properties according to your preferences.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the configuration of the Worldmap custom node&quot; alt=&quot;&amp;quot;Screenshot displaying the configuration of the Worldmap custom node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-worldmap-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;With the &lt;strong&gt;worldmap&lt;/strong&gt; node configured, it will generate a world map with plotted data accessible at the specified path.&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;Function&lt;/strong&gt; node&#39;s output to &lt;strong&gt;Worldmap&lt;/strong&gt; node&#39;s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now we have successfully created a page with a world map displaying plotted vehicle location data. To confirm, you can visit &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/worldmap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;rendering-map-on-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#rendering-map-on-dashboard-2.0&quot;&gt;Rendering map on Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To render worlmap webpage on dashboard 2.0 we will use &lt;strong&gt;iframe&lt;/strong&gt; custom widget which will allow us to embed an external webpage into Dashboard 2.0 applications using an iframe.&lt;/p&gt;
&lt;h3 id=&quot;installing-iframe-custom-widget&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#installing-iframe-custom-widget&quot;&gt;Installing iframe custom widget&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Click the Node-RED Settings (top-right)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Manage Palette&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Install&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;@flowfuse/node-red-dashboard-2-ui-iframe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;rendering-worlmap-on-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#rendering-worlmap-on-dashboard-2.0&quot;&gt;Rendering worlmap on Dashboard 2.0&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;iframe&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;ui-group&lt;/strong&gt; and &lt;strong&gt;ui-base&lt;/strong&gt; for it, where you want to render the webpage.&lt;/li&gt;
&lt;li&gt;Set height and width for it according to your preference and set URL to &lt;strong&gt;/worlmap&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing configurations of iframe widget for rendering worlmap page on dashboard&quot; alt=&quot;&amp;quot;Screenshot showing configurations of iframe widget for rendering worlmap page on dashboard&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-iframe-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#deploying-the-flow&quot;&gt;Deploying the flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image displaying live locations of UK public transport on the dashboard&quot; alt=&quot;&amp;quot;Image displaying live locations of UK public transport on the dashboard&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mapping-location-on-dashboard-2-uk-live-transport.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-181&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow181 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;b6917d83.d1bac&#92;&quot;,&#92;&quot;3842171.4d487e8&#92;&quot;,&#92;&quot;b4f2e2dabd5b8220&#92;&quot;,&#92;&quot;5f0d149d4dc38916&#92;&quot;,&#92;&quot;2ff7e9501ad50cd5&#92;&quot;,&#92;&quot;a08f0a836ac412a7&#92;&quot;,&#92;&quot;bc891dc2aaaedc39&#92;&quot;,&#92;&quot;726a8da3fe930e54&#92;&quot;,&#92;&quot;b3dd7814ea5270ca&#92;&quot;,&#92;&quot;0c5d6bcfd71d40da&#92;&quot;,&#92;&quot;e037ee3d1f702d25&#92;&quot;,&#92;&quot;d7ca6c3cdf176e4e&#92;&quot;],&#92;&quot;x&#92;&quot;:814,&#92;&quot;y&#92;&quot;:759,&#92;&quot;w&#92;&quot;:1872,&#92;&quot;h&#92;&quot;:322},{&#92;&quot;id&#92;&quot;:&#92;&quot;b6917d83.d1bac&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;https://tfe-opendata.com/api/v1/vehicle_locations&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:1190,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a08f0a836ac412a7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3842171.4d487e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;get transporatation data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:970,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b6917d83.d1bac&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4f2e2dabd5b8220&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;worldmap&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;worldmap&#92;&quot;,&#92;&quot;lat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;lon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;zoom&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layer&#92;&quot;:&#92;&quot;OSMG&#92;&quot;,&#92;&quot;cluster&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;maxage&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;usermenu&#92;&quot;:&#92;&quot;show&#92;&quot;,&#92;&quot;layers&#92;&quot;:&#92;&quot;show&#92;&quot;,&#92;&quot;panit&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;panlock&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;zoomlock&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;hiderightclick&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;coords&#92;&quot;:&#92;&quot;mgrs&#92;&quot;,&#92;&quot;showgrid&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;showruler&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;allowFileDrop&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/worldmap&#92;&quot;,&#92;&quot;overlist&#92;&quot;:&#92;&quot;DR,CO,RA,DN&#92;&quot;,&#92;&quot;maplist&#92;&quot;:&#92;&quot;OSMG,OSMC,EsriC,EsriS,UKOS&#92;&quot;,&#92;&quot;mapname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mapurl&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mapopt&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mapwms&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2600,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5f0d149d4dc38916&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Retrieving, formatting, and plotting location data on a world map.&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1390,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2ff7e9501ad50cd5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Rendering a map with plotted data on Dashboard 2.0.&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1440,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a08f0a836ac412a7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set payload&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.vehicles&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1390,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;726a8da3fe930e54&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bc891dc2aaaedc39&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Change and delete properties&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lat&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.latitude&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.latitude&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lon&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.longitude&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.longitude&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.color&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;blue&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.name&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.vehicle_id&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.vehicle_id&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1770,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b3dd7814ea5270ca&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;726a8da3fe930e54&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1550,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bc891dc2aaaedc39&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b3dd7814ea5270ca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;is vehical type is tram&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload.vehicle_type&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;tram&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;else&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:2,&#92;&quot;x&#92;&quot;:2040,&#92;&quot;y&#92;&quot;:900,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0c5d6bcfd71d40da&#92;&quot;],[&#92;&quot;e037ee3d1f702d25&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c5d6bcfd71d40da&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;set icon and icon color for tram&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.icon&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;fa-train&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.iconColor&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;yellow&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2310,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4f2e2dabd5b8220&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e037ee3d1f702d25&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;set icon and icon color for bus&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.icon&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;bus&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.iconColor&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;red&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:2310,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4f2e2dabd5b8220&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d7ca6c3cdf176e4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-iframe&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;eacc68e72f120b0e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;4e45e8ef870b86fb&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;15d2dfa55e99ea43&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;src&#92;&quot;:&#92;&quot;/worldmap&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;x&#92;&quot;:1370,&#92;&quot;y&#92;&quot;:1040,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;15d2dfa55e99ea43&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;U.K Transportation Live&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;e098e3047b4a4eaa&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;e098e3047b4a4eaa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;U.K Transportation Live&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;c2e1aa56f50f03bd&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/worldmap&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;earth&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;129e99574def90a3&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;c2e1aa56f50f03bd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;129e99574def90a3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Another Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#ff4000&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#f0f0f0&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#d9d9d9&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;9px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;9px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;6px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow181.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-181&#39;) })&lt;/script&gt;
&lt;ol&gt;
&lt;li&gt;With your flow updated to include the above, click the &lt;strong&gt;Deploy&lt;/strong&gt; button in the top-right of the Node-RED Editor.&lt;/li&gt;
&lt;li&gt;Locate the &lt;strong&gt;Open Dashboard&lt;/strong&gt; button at the top-right corner of the Dashboard 2.0 sidebar and click on it to navigate to the dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you can view the live location of Edinburgh public transport vehicles on the dashboard. Additionally, clicking on each vehicle reveals further details such as its name, speed, and other properties you&#39;ve included. Moreover, if you wish to track the live locations of your own vehicles instead of Edinburgh&#39;s public transport vehicles, you can connect your devices and access GPS and sensor data using the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;Flowfuse device agent&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/mapping-location-on-dashboard-2/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, this guide shows an easy way to map location data on Dashboard 2.0. By following these steps, you can make interactive dashboards that give you real-time info, useful for things like managing fleets and tracking logistics.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/</id>
        <title>Comprehensive guide: Node-RED Dashboard 2.0 layout, sidebar, and styling</title>
        <summary>Explore Dashboard 2.0 Different layouts and sidebars. learn how to style Dashboard 2.0 elements effortlessly.</summary>
        <updated>2024-05-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In this comprehensive guide, we will explore different layouts and sidebar styles in Dashboard 2.0. Additionally, we will cover how you can style Dashboard 2.0 elements effortlessly.&lt;/p&gt;
&lt;p&gt;If you are new to Dashboard 2.0, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting started with Node-RED Dashboard 2.0&lt;/a&gt; and make sure you have installed it.&lt;/p&gt;
&lt;h2 id=&quot;understanding-dashboard-2.0-layouts.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#understanding-dashboard-2.0-layouts.&quot;&gt;Understanding Dashboard 2.0 layouts.&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A layout in Node-RED Dashboard 2.0 refers to how groups of widgets are organized and arranged on a page. It controls the visual structure and placement of these widget groups to create an organized and easy-to-use interface.&lt;/p&gt;
&lt;h3 id=&quot;exploring-dashboard-2.0-layouts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#exploring-dashboard-2.0-layouts&quot;&gt;Exploring Dashboard 2.0 layouts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Dashboard 2.0, we have three types of layouts: Grid, Notebook, and Fixed.&lt;/p&gt;
&lt;h4 id=&quot;grid-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#grid-layout&quot;&gt;Grid layout&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Choosing this layout divides your dashboard page into &lt;strong&gt;12 equally-sized columns&lt;/strong&gt;, and you can specify how many columns your group will occupy using the &lt;code&gt;size&lt;/code&gt; property. When groups within a row take up all available columns, a new row automatically starts. The height of each row is determined by the tallest widget in that row.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of dashboard having grid layout&quot; alt=&quot;&amp;quot;Screenshot of dashboard having grid layout&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-grid-layout.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In the image above, you can see that the first and last widget groups occupy all 12 columns, while in the middle, two groups each take up six columns.&lt;/p&gt;
&lt;h4 id=&quot;notebook-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#notebook-layout&quot;&gt;Notebook layout&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Choosing the Notebook layout for your page in Dashboard 2.0 makes it work like a Jupyter Notebook, fixed at a width of &lt;strong&gt;1024px&lt;/strong&gt; and &lt;strong&gt;centered&lt;/strong&gt;. Here, a groups&#39; &amp;quot;width&amp;quot; defines the number of columns the group contains. The group itself will always render the full width of the Notebook. It&#39;s great for dynamic Markdown, data tables, and visuals. Groups of pages are stacked vertically.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of dashboard having notebook layout&quot; alt=&quot;&amp;quot;Screenshot of dashboard having notebook layout&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-notebook-layout.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;fixed-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#fixed-layout&quot;&gt;Fixed layout&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this layout, the width value is converted to &amp;quot;units&amp;quot;, with each unit being &lt;code&gt;90px&lt;/code&gt; wide. For example, if you set the group width to &lt;code&gt;3&lt;/code&gt;, it will be 3 * 90 = 270px wide. Within a given group, the group size represents a column in the group&#39;s internal grid, following the same pattern as other layouts.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of dashboard having fixed layout&quot; alt=&quot;&amp;quot;Screenshot of dashboard having fixed layout&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-fix-layout.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Currently this layout is not optimised, with plans to make it similar to Dashboard 1.0 in how it compresses content vertically, so it is recommended to use other layouts.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;setting-page-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-page-layout&quot;&gt;Setting page layout&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the page configuration by clicking on the &lt;strong&gt;edit&lt;/strong&gt; button of your page in the Dashboard 2.0 sidebar.&lt;/li&gt;
&lt;li&gt;In the page configuration, you can select the preferred layout for that page within the layout field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing process of setting page layout&quot; alt=&quot;&amp;quot;Image showing process of setting page layout&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-setting-new-page-layout.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting-dashboard-2.0-elements-size&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-dashboard-2.0-elements-size&quot;&gt;Setting Dashboard 2.0 elements size&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Setting the size for elements in Dashboard 2.0 is straightforward, but understanding the actual unit size in the size property can be a bit tricky.&lt;/p&gt;
&lt;p&gt;It&#39;s important to note that the size of a single horizontal unit varies depending on the layout, but the vertical size of a single row is consistently &lt;strong&gt;48px&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;sizing-widgets-within-a-group&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#sizing-widgets-within-a-group&quot;&gt;Sizing Widgets within a Group&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In any layout—Grid, Notebook, or Fixed—widgets within a group are sized using a unified approach. The size property assigned to widgets determines their width within the group. Each unit in the size property represents a fraction of the group&#39;s total width. This width is determined by an internal grid established by the group.&lt;/p&gt;
&lt;h3 id=&quot;widget-sizing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#widget-sizing&quot;&gt;Widget Sizing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Widgets are sized relative to the number of columns in the internal grid. For example, if a group has 4 columns and two widgets, and the first widget is set to 1 width while the second to 3 width, the first widget will occupy 25% of the group&#39;s width, and the second widget will occupy 75%.&lt;/p&gt;
&lt;p&gt;Regardless of the layout type, the concept of sizing widgets within a group remains consistent. Whether it&#39;s the grid, notebook, or fixed layout, the same principles apply, ensuring uniformity in widget layout and design.&lt;/p&gt;
&lt;h3 id=&quot;setting-element-size&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-element-size&quot;&gt;Setting element size&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To set the size of groups and widgets in Dashboard 2.0, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the Dashboard 2.0 sidebar and click on the edit button next to the element you want to resize.&lt;/li&gt;
&lt;li&gt;Adjust the size using the size property.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing process of setting element size&quot; alt=&quot;&amp;quot;Image showing process of setting element size&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-setting-size.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;understanding-dashboard-2.0-theme&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#understanding-dashboard-2.0-theme&quot;&gt;Understanding Dashboard 2.0 Theme&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The theme is a collection of colors that control the look and feel of the widgets, groups, and other elements on the page.&lt;/p&gt;
&lt;p&gt;In Dashboard 2.0, when adding a page ( ui-page ) we can specify which theme it will use. By default, we have one theme in Dashboard 2.0, we can add more themes using the Dashboard 2.0 side panel.&lt;/p&gt;
&lt;h3 id=&quot;understanding-theme-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#understanding-theme-properties&quot;&gt;Understanding theme properties&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the theme (&lt;code&gt;ui-theme&lt;/code&gt;) configuration, there are two main sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Colors:&lt;/strong&gt; Specify colors for Navigation, primary elements, page background, group backgrounds, and outlines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sizing:&lt;/strong&gt; Define the gaps between groups, page padding, group outline radius, and gaps between widgets, all in pixels.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For additional information on the &lt;code&gt;ui-theme&lt;/code&gt; settings, please refer to the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/config/ui-theme.html&quot;&gt;ui-theme documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;setting-a-new-page-theme&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-a-new-page-theme&quot;&gt;Setting a new page theme&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the Dashboard 2.0 sidebar and switch to the theme tab.&lt;/li&gt;
&lt;li&gt;Click on the top-right “+theme” button to add a new theme.&lt;/li&gt;
&lt;li&gt;After specifying colors and sizing click on the top right update button to save the theme.&lt;/li&gt;
&lt;li&gt;Now switch to the layout tab and click on the edit button next to the page for which you want to set a new theme.&lt;/li&gt;
&lt;li&gt;In the page config, select the newly added theme in the Theme field.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing process of adding new theme&quot; alt=&quot;&amp;quot;Image showing process of adding new theme&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-adding-new-theme.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;dashboard-2.0-navigation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#dashboard-2.0-navigation&quot;&gt;Dashboard 2.0 Navigation&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;setting-sidebar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#setting-sidebar&quot;&gt;Setting sidebar&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the Dashboard 2.0 sidebar in the Node-RED editor&lt;/li&gt;
&lt;li&gt;Click on the &amp;quot;Edit Settings&amp;quot; button located at the top left side of the Dashboard 2.0 sidebar.&lt;/li&gt;
&lt;li&gt;Select your preferred sidebar style from the &amp;quot;Style&amp;quot; field in the sidebar options section.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing process of changing sidebar style&quot; alt=&quot;&amp;quot;Image showing process of changing sidebar style&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-setting-sidebar.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;sidebar-navigation-options&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#sidebar-navigation-options&quot;&gt;Sidebar Navigation Options&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Dashboard 2.0, we have 5 different navigation options for your application.&lt;/p&gt;
&lt;h4 id=&quot;collapsing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#collapsing&quot;&gt;Collapsing&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is the default sidebar, when it&#39;s opened, the page content adjusts to the width of the sidebar.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing Collapsing sidebar&quot; alt=&quot;&amp;quot;Image showing &#39;Collapsing&#39; sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-collapsing-sidebar.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can see in the image above how the page content automatically adjusts when the sidebar is opened.&lt;/p&gt;
&lt;h4 id=&quot;fixed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#fixed&quot;&gt;Fixed&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this type, the sidebar is always visible and fixed on the left side, and the top menu icon is hidden. The page content adjusts to the width of the sidebar.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing Fixed sidebar&quot; alt=&quot;&amp;quot;Image showing &#39;Fixed&#39; sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-fixed-layout.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;collapse-to-icon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#collapse-to-icon&quot;&gt;Collapse to icon&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This type of sidebar is similar to the collapsible one, but when the sidebar is collapsed, you can still navigate through different pages as the page icons become visible.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image showing Collapse to icon sidebar&quot; alt=&quot;&amp;quot;Image showing &#39;Collapse to icon&#39; sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-collaps-to-icon-sidebar.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;apear-over-content&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#apear-over-content&quot;&gt;Apear over content&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When the sidebar is opened, the page is partially covered by a transparent layer, and the sidebar appears on top of this layer&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;screenshot displaying searching for botFather bot for creating custom bot&quot; alt=&quot;&amp;quot;Image showing &#39;Apear over content&#39; sidebar&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-appear-over-content.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In this type of sidebar, you can notice how the sidebar opens without affecting the width of the page content&lt;/p&gt;
&lt;h4 id=&quot;always-hide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#always-hide&quot;&gt;Always hide&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this type, the sidebar is always hidden, and navigation between different pages can be achieved using the ui-control widget.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;screenshot displaying searching for botFather bot for creating custom bot&quot; alt=&quot;&amp;quot;screenshot displaying searching for botFather bot for creating custom bot&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-always-hidden.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;customising-your-dashboard-2.0-further&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#customising-your-dashboard-2.0-further&quot;&gt;Customising your Dashboard 2.0 further&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Dashboard 2.0, we can add classes to almost all widgets, pages, and groups and style them using CSS.&lt;/p&gt;
&lt;h3 id=&quot;adding-classes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#adding-classes&quot;&gt;Adding classes&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;To add classes to your widget, page, or group, you&#39;ll need to open its configuration&lt;/li&gt;
&lt;li&gt;Find the &#39;Class&#39; field and enter your class.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing the class property input field&quot; alt=&quot;&amp;quot;Screenshot showing the class property input field&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-showing-class-property-feild.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;writing-custom-css&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#writing-custom-css&quot;&gt;Writing custom CSS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Dashboard 2.0, the &lt;code&gt;ui-template&lt;/code&gt; node allows you to write custom CSS for Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;In the template node, you can add CSS for two different scopes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single Page:&lt;/strong&gt; Selecting this allows you to specify CSS that is constrained to a single page of your dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All Pages:&lt;/strong&gt; Selecting this allows you to define CSS that will apply across your whole dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To define your own CSS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an ui-template widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Double-click on it and select the scope within the type field.&lt;/li&gt;
&lt;li&gt;If you select the &amp;quot;CSS (Single Page)&amp;quot; type, you&#39;ll then need to select the &lt;code&gt;ui-page&lt;/code&gt; to which your custom class definitions will apply. If you select the &amp;quot;CSS (All Pages)&amp;quot; type, then you&#39;ll need to select the &lt;code&gt;ui-base&lt;/code&gt; that includes those pages to which you want to add styling.&lt;/li&gt;
&lt;li&gt;Now you can write your custom CSS within the ui-template.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Image displaying the left side with the page and group where custom CSS has been applied, and the right side showcasing the UI-template with the corresponding CSS&quot; alt=&quot;&amp;quot;Image displaying the left side with the page and group where custom CSS has been applied, and the right side showcasing the UI-template with the corresponding CSS&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-dashboard-2-layout-navigation-styling-adding-style.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;up-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/node-red-dashboard-2-layout-navigation-styling/#up-next&quot;&gt;Up Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To delve deeper into Node-RED Dashboard 2.0, we recommend exploring the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/dashboard/&quot;&gt;FlowFuse Dashboard Articles&lt;/a&gt; - Collection of examples and guides written by FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0 Documentation&lt;/a&gt; - Detailed information for each of the nodes available in Dashboard 2.0, as well as useful guides on building custom nodes and widgets of your own.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.nodered.org/tag/dashboard-2&quot;&gt;Node-RED Forums - Dashboard 2.0&lt;/a&gt; - The Node-RED forums are a great place to ask questions, share your projects and get help from the community.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;Beginner Guide to a Professional Node-RED&lt;/a&gt; - A free guide to an enterprise-ready Node-RED. Learn all about Node-RED history, securing your flows, and dashboard data visualization.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/</id>
        <title>FlowFuse 2.4: making it easier to work with Snapshots, Blueprints &amp; Devices</title>
        <summary>Our latest release introduces better ways to work with Snapshots, Blueprints, view the content of you flows in FlowFuse, and manage the version of Node-RED running on Devices</summary>
        <updated>2024-05-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;FlowFuse 2.4 introduces better ways to work with Snapshots, Blueprints, view the content of you flows in FlowFuse, and manage the version of Node-RED running on Devices&lt;/p&gt;
&lt;h2 id=&quot;export-snapshots-from-flowfuse-%233627&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#export-snapshots-from-flowfuse-%233627&quot;&gt;Export Snapshots from FlowFuse &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3627&quot;&gt;#3627&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can now export your Snapshots of your Node-RED instances. This is our first step towards making it easier to move Snapshots in and out or your FlowFuse projects, as well as share them with other teams. We will be adding many more Snapshot management features over the next few releases.&lt;/p&gt;
&lt;h2 id=&quot;easier-creation-of-node-red-instances-from-blueprints-%233729&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#easier-creation-of-node-red-instances-from-blueprints-%233729&quot;&gt;Easier creation of Node-RED instances from Blueprints &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3729&quot;&gt;#3729&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We introduced our library of Node-RED &lt;a href=&quot;https://flowfuse.com/blog/2023/10/blueprints/&quot;&gt;Blueprints&lt;/a&gt; in October 2023. FlowFuse Blueprints aim to make the Node-RED experience more accessible for newcomers, while also offering a treasure trove of fresh ideas for seasoned Node-RED users. In this release, we are making it even easier to start a new Node-RED instance based on a Blueprint from our library.&lt;/p&gt;
&lt;h2 id=&quot;view-flows-within-the-team-library-without-loading-node-red-%233803&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#view-flows-within-the-team-library-without-loading-node-red-%233803&quot;&gt;View Flows within the Team Library without loading Node-RED &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3803&quot;&gt;#3803&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In September 2023, Node-RED community member &lt;a href=&quot;https://github.com/gorenje&quot;&gt;gorenje&lt;/a&gt; created some code that could be used to visualise Node-RED flows without having to load the full Node-RED editor. This was added to the community &lt;a href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/&quot;&gt;flow library&lt;/a&gt; and has proven to be a great addition.&lt;/p&gt;
&lt;p&gt;With gorenje&#39;s support, we&#39;ve packaged up his library to make it easier to embed in other sites and have made it generally available &lt;a href=&quot;https://github.com/FlowFuse/flow-renderer&quot;&gt;here&lt;/a&gt;. A big thanks to gorenje for laying the ground work and allow us to build on it.&lt;/p&gt;
&lt;p&gt;We&#39;ve wasted no time putting this to good use within FlowFuse. Our first step is in our &lt;a href=&quot;https://flowfuse.com/changelog/2024/05/library-flowviewer/&quot;&gt;Team Library&lt;/a&gt;. You can now view a visual representation of saved flows in your Team Library.&lt;/p&gt;
&lt;h2 id=&quot;view-flows-within-snapshots-without-loading-node-red-%233798&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#view-flows-within-snapshots-without-loading-node-red-%233798&quot;&gt;View Flows within Snapshots without loading Node-RED &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/3798&quot;&gt;#3798&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The second place we are adding the ability to preview flows is to the Snapshots interface. Again, based on &lt;a href=&quot;https://github.com/gorenje/node-red-flowviewer-js&quot;&gt;node-red-flowviewer-js&lt;/a&gt;, the Flow Viewer will make loading the snapshot you need into your Node-RED instance quicker and easier.&lt;/p&gt;
&lt;h2 id=&quot;manage-node-red-versions-on-devices-%233766&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#manage-node-red-versions-on-devices-%233766&quot;&gt;Manage Node-RED versions on Devices &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/3766&quot;&gt;#3766&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It can be useful to select a specific version of Node-RED to run, for example where you are using a custom node which only runs on specific versions of Node-RED. In this release we have added the ability to easily select the version of Node-RED you wish to run on your devices.&lt;/p&gt;
&lt;h2 id=&quot;full-list-of-release-features-and-bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#full-list-of-release-features-and-bug-fixes&quot;&gt;Full list of release features and bug fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can view everything included in 2.4 on the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v2.4.0&quot;&gt;Github Release page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also regularly release updates to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; in between our monthly releases. You can follow the updates as they are made via our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;ChangeLog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 2.4.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/flowfuse-2-4-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/</id>
        <title>Node-RED Variables: Global, Flow, Context &amp; Environment Variables Complete Guide</title>
        <summary>Guide to Understanding and Managing Node-RED Variables for Efficient Workflows</summary>
        <updated>2024-05-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Variables are essential for building anything beyond basic message routing in Node-RED. They let you store state, share data across your application, and manage configuration—capabilities you&#39;ll need for almost any real-world project.&lt;/p&gt;
&lt;p&gt;Node-RED provides four types of variables, each with different visibility and use cases. This guide walks through each one, showing you exactly how to set, retrieve, and delete them, along with practical guidance on which type to use in different situations.&lt;/p&gt;
&lt;h2 id=&quot;what-are-node-red-variables%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#what-are-node-red-variables%3F&quot;&gt;What Are Node-RED Variables?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Variables in Node-RED serve as containers for storing and managing data throughout your application. Understanding the different types and their scopes is essential for building efficient, organized flows.&lt;/p&gt;
&lt;p&gt;Node-RED offers three primary variable categories:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Message variables&lt;/strong&gt; travel with the message object as it flows through your nodes. The most common example is &lt;code&gt;msg.payload&lt;/code&gt;, which carries the primary data between nodes. For a deeper dive into message handling, see the &lt;a href=&quot;https://flowfuse.com/node-red/getting-started/node-red-messages/&quot;&gt;Understanding Node-RED Messages&lt;/a&gt; guide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Context variables&lt;/strong&gt; store application state at different levels—node, flow, or global scope. They persist data that needs to be accessed across multiple message events, making them ideal for tracking counters, storing configuration, or maintaining state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Environment variables&lt;/strong&gt; handle configuration data and sensitive information like API keys and credentials. By storing this data separately from your flows, you maintain security and make configuration management more flexible.&lt;/p&gt;
&lt;h2 id=&quot;global-variables%3A-instance-wide-data-storage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#global-variables%3A-instance-wide-data-storage&quot;&gt;Global Variables: Instance-Wide Data Storage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Global variables provide a centralized storage mechanism accessible throughout your entire Node-RED instance. Any function, change, inject, or switch node can read or write global variables, making them perfect for sharing data across multiple flows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use global variables:&lt;/strong&gt; Consider using them for system-wide settings, shared configuration, or data that multiple flows need to access. For example, in a home automation system with separate flows for lighting, security, and climate control, global variables can store user preferences that all flows reference.&lt;/p&gt;
&lt;h3 id=&quot;working-with-global-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#working-with-global-variables&quot;&gt;Working with Global Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Setting global variables&lt;/strong&gt; can be done through the change node or programmatically in a function node:&lt;/p&gt;
&lt;p&gt;Using the change node:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &amp;quot;global&amp;quot; from the variable type dropdown&lt;/li&gt;
&lt;li&gt;Enter your variable name&lt;/li&gt;
&lt;li&gt;Set the value or expression&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to set global variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to set global variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-setting-global-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Using a function node:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-65&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-65&quot; class=&quot;language-javascript&quot;&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;userName&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;John&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;systemMode&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;active&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-65&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Retrieving global variables&lt;/strong&gt; follows a similar pattern:&lt;/p&gt;
&lt;p&gt;In a change, inject, or switch node, simply set the action to “set”, choose the type as “global”, and specify the variable name.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to retrieve global variables using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to retrieve global variables using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-retrieving-global-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-78&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-78&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;userName&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;systemMode&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-78&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Deleting global variables&lt;/strong&gt; can be accomplished through the change node by selecting &amp;quot;delete&amp;quot; from the action dropdown, or via the Context Data sidebar panel, which provides a comprehensive view of all variables.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to delete global variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to delete global variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-deleting-global-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;flow-variables%3A-tab-scoped-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#flow-variables%3A-tab-scoped-data&quot;&gt;Flow Variables: Tab-Scoped Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Flow variables exist within a single tab or flow in your Node-RED editor. They&#39;re accessible to all nodes within that specific flow but isolated from other flows, providing logical data separation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use flow variables:&lt;/strong&gt; Use them for data that&#39;s relevant only to a specific workflow. For instance, in a temperature monitoring flow with multiple sensor nodes, flow variables can track the current reading, alert thresholds, or calculation results—data that doesn&#39;t need to be shared with other parts of your application.&lt;/p&gt;
&lt;h3 id=&quot;working-with-flow-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#working-with-flow-variables&quot;&gt;Working with Flow Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Setting flow variables:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using the change node, select the action “set”, choose “flow” as the variable type, and configure your variable.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to set flow variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to set flow variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-setting-flow-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-109&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-109&quot; class=&quot;language-javascript&quot;&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;currentTemp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;alertThreshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-109&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Retrieving flow variables:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a change, inject, or switch node, simply set the action to “set”, choose the type as “flow”, and specify the variable name.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to retrieve flow variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to retrieve flow variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-retrieving-flow-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-122&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-122&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;currentTemp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; threshold &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;alertThreshold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-122&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Deleting flow variables&lt;/strong&gt; works the same way as global variables—use the change node&#39;s delete action or the Context Data panel.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to delete flow variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to delete flow variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-deleting-flow-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;node-variables%3A-node-level-isolation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#node-variables%3A-node-level-isolation&quot;&gt;Node Variables: Node-Level Isolation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node variables (also called node context) are the most restrictive scope—they exist only within a single node. No other node can access or modify these variables, making them ideal for maintaining private state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When to use node variables:&lt;/strong&gt; Perfect for counters, temporary calculations, or any data that should remain private to a specific node. For example, a function node that generates unique IDs for database records can maintain a counter variable that&#39;s never exposed to other parts of your flow.&lt;/p&gt;
&lt;h3 id=&quot;working-with-node-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#working-with-node-variables&quot;&gt;Working with Node Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node variables are local to a Function node and cannot be read or modified by other nodes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting node variables:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-147&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-147&quot; class=&quot;language-javascript&quot;&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lastProcessedId&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ABC123&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-147&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Retrieving node variables:&lt;/strong&gt;&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-151&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-151&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;counter&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-151&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Deleting node variables&lt;/strong&gt; must be done through the Context Data sidebar panel.&lt;/p&gt;
&lt;h2 id=&quot;persistent-storage-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#persistent-storage-with-flowfuse&quot;&gt;Persistent Storage with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, all context variables (node, flow, and global) are stored in memory. This means they&#39;re lost whenever you restart Node-RED or redeploy your flows. For production applications, this is often unacceptable.&lt;/p&gt;
&lt;p&gt;FlowFuse provides persistent storage that survives restarts, redeployments, and system updates. This ensures your application state remains intact across sessions.&lt;/p&gt;
&lt;h3 id=&quot;using-persistent-storage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#using-persistent-storage&quot;&gt;Using Persistent Storage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Setting persistent variables:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the change node, select &amp;quot;persistent&amp;quot; from the store dropdown instead of &amp;quot;memory&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to set global variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to set global variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-change-node-persistent-store-option-for-while-setting-variable.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes, add &amp;quot;persistent&amp;quot; as a third parameter:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-179&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-179&quot; class=&quot;language-javascript&quot;&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;userData&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sessionConfig&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;processedCount&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-179&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Retrieving persistent variables:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a change, inject, or switch node, ensure you&#39;re selecting from the &amp;quot;persistent&amp;quot; store.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to retrieve global variable using the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to retrieve global variable using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-change-node-persistent-store-option.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-192&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-192&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;userData&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sessionConfig&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;processedCount&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;persistent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-192&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Persistent storage allows Node-RED to retain state between restarts—crucial for historical metrics, long-running counters, dashboard application data, and any flow that must persist through a reboot without losing information.&lt;/p&gt;
&lt;h2 id=&quot;the-context-data-panel&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#the-context-data-panel&quot;&gt;The Context Data Panel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED includes a dedicated Context Data panel in the sidebar that provides visibility into all your variables. This panel is invaluable for debugging and understanding your application&#39;s state.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing Node-RED Context data tab&quot; alt=&quot;&amp;quot;Screenshot showing Node-RED Context data tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-context-data-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Features of the Context Data panel:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View all node, flow, and global variables in organized sections&lt;/li&gt;
&lt;li&gt;See when each variable was last updated&lt;/li&gt;
&lt;li&gt;Copy variable names or values with one click&lt;/li&gt;
&lt;li&gt;Refresh individual variables to see current values&lt;/li&gt;
&lt;li&gt;Delete variables directly from the interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To access this panel, open the sidebar and choose ‘Context Data’ from the dropdown menu. Use the refresh icon in each section to update the display with the latest values.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing Node-RED Context data tab options for managing variables&quot; alt=&quot;&amp;quot;Screenshot showing Node-RED Context data tab options for managing variables&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-context-data-tab-options-for-varrables.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;environment-variables%3A-secure-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#environment-variables%3A-secure-configuration&quot;&gt;Environment Variables: Secure Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Environment variables serve a different purpose than context variables—they&#39;re designed for configuration data, especially sensitive information that shouldn&#39;t be hardcoded in your flows.&lt;/p&gt;
&lt;p&gt;Node-RED supports environment variables at two levels:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flow-level environment variables&lt;/strong&gt; are accessible only within a specific flow. This is useful when different flows need different configurations. For example, one flow might connect to a development database while another connects to production, each using its own credentials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Global-level environment variables&lt;/strong&gt; are accessible across all flows in your instance. Use these for shared configuration like API keys that multiple flows need to reference.&lt;/p&gt;
&lt;h3 id=&quot;working-with-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#working-with-environment-variables&quot;&gt;Working with Environment Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Setting flow-level environment variables:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Double-click on the flow tab to open the edit dialog&lt;/li&gt;
&lt;li&gt;Navigate to the &amp;quot;Environment Variables&amp;quot; section&lt;/li&gt;
&lt;li&gt;Add your variables as name-value pairs&lt;/li&gt;
&lt;li&gt;Click Done and deploy&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to set flow level environment variables&quot; alt=&quot;&amp;quot;Screenshot showing how to set flow level environment variables&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-setting-flow-scope-enviroment-variable.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For global-level environment variables, see &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt; for detailed instructions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Accessing environment variables:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In change, inject, or switch nodes, select &amp;quot;env variable&amp;quot; and specify the name.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot showing how to retrieve environment variable in the change node&quot; alt=&quot;&amp;quot;Screenshot showing how to retrieve environment variable in the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/variables-in-node-red-retrieving-environment-variable-using-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In function nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-302&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-302&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; apiKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;API_KEY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dbHost &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-302&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;In template nodes:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-306&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-306&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;API&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;Endpoint&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-306&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;For configuration nodes that don&#39;t have explicit environment variable support, you can often use the syntax &lt;code&gt;${VARIABLE_NAME}&lt;/code&gt; in input fields.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important note on precedence:&lt;/strong&gt; When a flow-level and global-level environment variable share the same name, Node-RED uses the flow-level value. To explicitly access the global-level variable, prefix it with &lt;code&gt;$parent.&lt;/code&gt; in your reference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deleting environment variables:&lt;/strong&gt; Return to the flow edit dialog where you added them and click the delete icon next to each variable. Remember to redeploy your flows after making changes.&lt;/p&gt;
&lt;h2 id=&quot;best-practices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#best-practices&quot;&gt;Best Practices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are some guidelines for effective variable usage in Node-RED:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Choose the right scope:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use node variables for node-specific data&lt;/li&gt;
&lt;li&gt;Use flow variables for data shared within a single workflow&lt;/li&gt;
&lt;li&gt;Use global variables for system-wide shared data&lt;/li&gt;
&lt;li&gt;Use environment variables for configuration and secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Naming conventions matter:&lt;/strong&gt; Use clear, descriptive names. Consider prefixing variables with their purpose (e.g., &lt;code&gt;sensor_temperature&lt;/code&gt;, &lt;code&gt;config_timeout&lt;/code&gt;, &lt;code&gt;user_preferences&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leverage persistent storage:&lt;/strong&gt; For production applications, identify which variables need to survive restarts and use persistent storage for those.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keep sensitive data in environment variables:&lt;/strong&gt; Never hardcode API keys, passwords, or other secrets directly in flows. Always use environment variables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Document your variables:&lt;/strong&gt; Use the description field in your nodes to explain what variables are being set or read, especially for complex flows that others might maintain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monitor the Context Data panel:&lt;/strong&gt; Regularly check this panel during development to verify variables are being set correctly and to catch potential issues early.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/05/understanding-node-flow-global-environment-variables-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mastering Node-RED&#39;s variable system transforms how you build applications. With context variables providing flexible state management and environment variables securing your configuration, you have all the tools needed for professional-grade deployments.&lt;/p&gt;
&lt;p&gt;As your Node-RED projects scale, you&#39;ll likely need more sophisticated tools for managing deployments, collaborating with teams, and ensuring reliability across environments. FlowFuse provides enterprise-grade features built specifically for Node-RED, including advanced persistent storage, team collaboration tools, and seamless deployment pipelines.&lt;/p&gt;
&lt;p&gt;Ready to take your Node-RED development to the next level? &lt;a href=&quot;https://app.flowfuse.com/account/create?utm_campaign=60718323-BCTA&amp;amp;utm_source=blog&amp;amp;utm_medium=cta&amp;amp;utm_term=high_intent&amp;amp;utm_content=Understanding%20Node%2C%20Flow%2C%20Global%2C%20and%20Environment%20Variables%20in%20Node-RED&quot;&gt;Start your FlowFuse journey today&lt;/a&gt; and experience Node-RED with professional-grade tooling and support.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/</id>
        <title>Dashboard 2.0: Milestones, PWA and New Components</title>
        <summary>Checkout all the great content that&#39;s been added to Dashboard 2.0 in the past few weeks and the new (in-preview) Vuetify components we&#39;ve made available in UI Template nodes.</summary>
        <updated>2024-04-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;With a new release of Node-RED Dashboard 2.0 we have plenty of new fixes and improvements being added to the project. In this post, we&#39;ll deep dive into community contributions, PWA support, new Vuetify components, and the rest of the great work published in this latest release.&lt;/p&gt;
&lt;h2 id=&quot;community-contributions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#community-contributions&quot;&gt;Community Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We firstly wanted to take this opportunity to point out a big milestone that we&#39;re very proud to see in Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;This release marks the first time we&#39;ve had more contributions in a single release from the community, than from FlowFuse employees. I think this is a testament to the community, and a big milestone in validating the success, and popularity, of Dashboard 2.0 in the wider Node-RED community.&lt;/p&gt;
&lt;p&gt;So thank you very much &lt;a href=&quot;https://github.com/bartbutenaers&quot;&gt;@BartButenaers&lt;/a&gt;, &lt;a href=&quot;https://github.com/Ek1nox&quot;&gt;@Ek1nox&lt;/a&gt;, &lt;a href=&quot;https://github.com/fullmetal-fred&quot;&gt;@fullmetal-fred&lt;/a&gt; and &lt;a href=&quot;https://github.com/cgjgh&quot;&gt;@cgjgh&lt;/a&gt; for for great efforts and initiative in improving Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;For anyone else that&#39;s interested in contributing to the project, please do reach out, and we&#39;ll be happy to help you get started. We also have a &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/&quot;&gt;Contributing Guide&lt;/a&gt; if you want to dive straight in.&lt;/p&gt;
&lt;h2 id=&quot;progressive-web-app-(pwa)-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#progressive-web-app-(pwa)-support&quot;&gt;Progressive Web App (PWA) Support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The biggest community contribution we saw in this release was the addition of Progressive Web App (PWA) support. This feature was added by &lt;a href=&quot;https://github.com/cgjgh&quot;&gt;@cgjgh&lt;/a&gt;, and allows you to install your Node-RED Dashboard 2.0 applications directly onto your platform, including Windows, iOS and Android.&lt;/p&gt;
&lt;p&gt;This work will give your Dashboard&#39;s a much more native/natural feel when running on your own machines, and mean you no longer need to go via your browser to access your applications.&lt;/p&gt;
&lt;h2 id=&quot;new-vuetify-(preview)-components-available&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#new-vuetify-(preview)-components-available&quot;&gt;New Vuetify (Preview) Components Available&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Vuetify is the component library on which most of our Dashboard 2.0 components are built. Our core widgets implement the more fundamental UI elements, but that doesn&#39;t stop you from building out fully customized interfaces yourself using our &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html&quot;&gt;ui-template node&lt;/a&gt; with the vast collection of Vuetify components.&lt;/p&gt;
&lt;p&gt;Within the &lt;code&gt;ui-template&lt;/code&gt; node, we natively support any of the &lt;a href=&quot;https://vuetifyjs.com/en/components/all/#containment&quot;&gt;core Vuetify components&lt;/a&gt;, but Vuetify itself is always evolving and often they release components into their &lt;a href=&quot;https://vuetifyjs.com/en/labs/introduction/#what-is-labs&quot;&gt;Vuetify Labs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In their latest releases, a few of the new components have caught our eye as we&#39;ve seen them regularly requested in Dashboard 2.0. As such, we&#39;ve now made available the following Vuetify components inside a &lt;code&gt;ui-template&lt;/code&gt; node:&lt;/p&gt;
&lt;h4 id=&quot;number-input-(docs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#number-input-(docs)&quot;&gt;Number Input (&lt;a href=&quot;https://vuetifyjs.com/en/components/number-inputs/#installation&quot;&gt;docs&lt;/a&gt;)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Number Input&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/vuetify-numeric.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An example v-number-input from Vuetify&#39;s component library&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We do have &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/41&quot;&gt;plans&lt;/a&gt; for this to become a core widget, and will likely introduce this sooner, rather than later, however, in the mean time, you can now use the &lt;code&gt;v-number-input&lt;/code&gt; component in a &lt;code&gt;ui-template&lt;/code&gt; node to create your own number inputs instead.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-48&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-48&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-number-input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-model&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-number-input&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function-variable function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;.v-number-input__control .v-btn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--v-theme-on-surface&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-48&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;sparkline-(docs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#sparkline-(docs)&quot;&gt;Sparkline (&lt;a href=&quot;https://vuetifyjs.com/en/components/sparklines/#installation&quot;&gt;docs&lt;/a&gt;)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Sparkline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/vuetify-sparkline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An example v-sparkline rendering the output from a ui-slider&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Sparklines are a great way to visualize data trends in a small space, and we&#39;ve seen them requested a few times in the past. Now you can use the &lt;code&gt;v-sparkline&lt;/code&gt; component in a &lt;code&gt;ui-template&lt;/code&gt; node to create your own sparklines.&lt;/p&gt;
&lt;p&gt;This will also likely become a standalone node at some point too, possibly as a third-party widget, but for now implementing into a &lt;code&gt;ui-template&lt;/code&gt; is very straight forward.&lt;/p&gt;
&lt;p&gt;In the following example &lt;code&gt;ui-template&lt;/code&gt;, we append any incoming &lt;code&gt;msg.payload&lt;/code&gt; to a &lt;code&gt;value&lt;/code&gt; array and render the sparkline accordingly.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-64&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-64&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-sparkline&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;nrdb-ui-sparkline&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:auto-line-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;false&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:gradient&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;gradient&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;:gradient-direction&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;top&#39;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:line-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:model-value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:padding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;:smooth&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;round&#39;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;trend&#39;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;auto-draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-sparkline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function-variable function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;gradient&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#f72047&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;#ffd200&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;#1feaea&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function-variable function&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.nrdb-ui-sparkline path&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;stroke-dasharray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0 &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-64&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;There is no limitation on &lt;em&gt;where&lt;/em&gt; you can use the sparkline either, we could, for example, add it to a &lt;code&gt;v-data-table&lt;/code&gt; to show a sparkline of a particular feature for each row in the table:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Data Table with Sparkline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/vuetify-data-table-sparkline.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An example v-data-table that renders a v-sparkline on each row&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here we see the corresponding template for the above &lt;code&gt;v-data-table&lt;/code&gt; example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-74&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-74&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Provide an input text box to search the content --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-text-field&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-model&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;prepend-inner-icon&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mdi-magnify&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;single-line&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;outlined&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;hide-details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-text-field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-data-table&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-model:&lt;/span&gt;search&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:items&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg?.payload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:headers&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;header.pingvalues&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            Ping History&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;item.ping&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            ms&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;item.pingvalues&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-sparkline&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-model&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item.pingValues&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:gradient&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[&#39;#42b3f4&#39;, &#39;#42b3f400&#39;]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token attr-name&quot;&gt;:line-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;gradientDirection&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:smooth&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-data-table&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ID&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ping&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ping&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;pingvalues&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Ping History&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-74&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;treeview-(docs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#treeview-(docs)&quot;&gt;Treeview (&lt;a href=&quot;https://vuetifyjs.com/en/components/treeview/#installation&quot;&gt;docs&lt;/a&gt;)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Treeview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/vuetify-treeview.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;An example v-treeview from Vuetify Lab&#39;s component library&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;v-treeview&lt;/code&gt; component is a great way to visualize hierarchical data in a tree-like structure. We&#39;ve seen this requested a few times in the past, and now you can use the &lt;code&gt;v-treeview&lt;/code&gt; component in a &lt;code&gt;ui-template&lt;/code&gt; node to create your own treeviews.&lt;/p&gt;
&lt;p&gt;There is still scope for this to, one day, become a core or third party widget, but in the mean time, it&#39;s very easy to get this up and running in a &lt;code&gt;ui-template&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;The Treeview example, and other examples above are available in this sample flow:&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;340px&quot; src=&quot;https://flows.nodered.org/flow/0ac4d82aaf97409cb0dce9812cfa214c/share?height=300&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;other-highlights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#other-highlights&quot;&gt;Other Highlights&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst the above are the main highlights of this release, we&#39;ve also had a number of other smaller improvements and fixes that have been added to the project. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Radio Group - Dynamic radio options in &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/765&quot;&gt;#765&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UI Notification - Notification output &amp;amp; output msg when button clicked in &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/766&quot;&gt;#766&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UI Dropdown - Clear dropdown selection in &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/775&quot;&gt;#775&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UI Button - Add &amp;quot;Emulate Click&amp;quot; option in &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/783&quot;&gt;#783&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the full list of changes in the &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v1.8.0&quot;&gt;1.8.0 Release Notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/dashboard-milestones-pwa-new-components/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;New features and improvements are coming to Node-RED Dashboard 2.0 every week, if you&#39;re interested in what we have lined up, or want to contribute yourself, then you can track the work we have lined up on our GitHub Projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/5&quot;&gt;Dashboard 1.0 Feature Parity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/</id>
        <title>How to Build An Application With Node-RED Dashboard 2.0</title>
        <summary>A step-by-step guide to building a personalized, secure, and fully functional application with Dashboard 2.0.</summary>
        <updated>2024-04-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;In this guide, we&#39;ll build a Todo application to guide you through the features and explain how you can build rich and dynamic applications too. It shows many of the features that make Dashboard 2.0 great, and why you should use it over the deprecated node-red-dashboard.&lt;/p&gt;
&lt;p&gt;If you&#39;re new to Dashboard 2.0, refer to our blog post &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard 2.0&lt;/a&gt; to install and get things started.&lt;/p&gt;
&lt;h2 id=&quot;installing-flowfuse-user-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#installing-flowfuse-user-addon&quot;&gt;Installing Flowfuse user addon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse User Addon is a plugin developed for Dashboard 2.0, that levereges the FlowFuse API to access logged in user&#39;s information at Dashboard 2.0. For detailed information refer to the &lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#exploring-the-flowfuse-user-addon&quot;&gt;Exploring the FlowFuse User Addon&lt;/a&gt; and make sure to install it.&lt;/p&gt;
&lt;p&gt;Before you begin the application development process, please make sure that FlowFuse user authentication is enabled. This feature adds a layer of security to your application with a login page. By combining the FlowFuse user addon with user authentication, we gain access to the logged in user&#39;s data within our application. For more information on FlowFuse user authentication, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/#flowfuse-user-authentication&quot;&gt;documentation&lt;/a&gt; and make sure that it is enabled.&lt;/p&gt;
&lt;h2 id=&quot;building-task-management-application&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#building-task-management-application&quot;&gt;Building Task Management application&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the task management system built with Node-RED Dashboard 2.0&quot; alt=&quot;&amp;quot;Screenshot of the Todo application built with Node-RED Dashboard 2.0&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-2-task-management-system.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Throughout this guide, we will be building a simple, secure, and personalized Task management application that will allow users to create and view their tasks.&lt;/p&gt;
&lt;h3 id=&quot;building-a-form-to-submit-tasks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#building-a-form-to-submit-tasks&quot;&gt;Building a Form to Submit Tasks&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ui-form&lt;/strong&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Click on the edit icon next to Page 1 (The default page added when you install Dashboard 2.0) in the Dashboard 2.0 sidebar. While this step is optional, updating the page configurations as shown in the image below ensures that your application aligns with the layout described in this guide.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying &#39;new task&#39; page configurations&quot; alt=&quot;&amp;quot;Screenshot displaying &#39;new task&#39; page configurations&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-2-page1-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on the &lt;strong&gt;ui-form&lt;/strong&gt; widget to add form elements such as title, description, due date, and priority.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of ui widget form configuration&quot; alt=&quot;&amp;quot;Screenshot of ui widget form configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-2-task-submission-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;storing-tasks-in-the-global-context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#storing-tasks-in-the-global-context&quot;&gt;Storing Tasks in the Global Context&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For this guide, we are storing our Tasks in Node-RED global context but storing them  in a database will make it easy to manage your task data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas&lt;/li&gt;
&lt;li&gt;Paste the below code in the &lt;strong&gt;function&lt;/strong&gt; node.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-70&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-70&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Retrieve the existing tasks from the global context or initialize an empty array if none exists&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; tasks &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;tasks&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Push the new task object into the tasks array, including the task details and the user object extracted from the message object, as each payload emitted by the Node-RED Dashboard 2.0 widgets contains user information due to the FlowFuse User Addon.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;tasks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user &lt;span class=&quot;token comment&quot;&gt;// Assign the user object to the task&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update the &#39;tasks&#39; variable in the global context with the modified tasks array&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;tasks&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tasks&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-70&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;ui-form&lt;/strong&gt; widget’s output to the &lt;strong&gt;function&lt;/strong&gt; node’s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;displaying-notification-on-successful-task-submission&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#displaying-notification-on-successful-task-submission&quot;&gt;Displaying notification on successful task submission&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;change&lt;/strong&gt; node onto the canvas and set &lt;code&gt;msg.payload&lt;/code&gt; to the confirmation message you want to display on successful task submission.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;screenshot of the change node setting payload for notification&quot; alt=&quot;&amp;quot;screenshot of the change node setting payload for notification&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-change-node-setting-payload-for-notification.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Drag an &lt;strong&gt;ui-notification&lt;/strong&gt; onto the canvas select &lt;strong&gt;ui-base&lt;/strong&gt; and set the position to &amp;quot;center&amp;quot;.&lt;/li&gt;
&lt;li&gt;Connect the &lt;strong&gt;ui-form&lt;/strong&gt; widget’s output to the &lt;strong&gt;change&lt;/strong&gt; node’s input and the &lt;strong&gt;change&lt;/strong&gt; node’s output to the &lt;strong&gt;ui-notification&lt;/strong&gt; widget&#39;s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;retrieving-and-filtering-tasks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#retrieving-and-filtering-tasks&quot;&gt;Retrieving and Filtering Tasks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we can store tasks along with the user details of who submitted them, we need to retrieve and filter them based on users, ensuring that users can only see their tasks only and not others.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;strong&gt;ui-event&lt;/strong&gt; widget onto the canvas and select &lt;strong&gt;ui-base&lt;/strong&gt; for it. The &lt;strong&gt;ui-event&lt;/strong&gt; will enable us to display updated tasks on the table without the need for polling, as it triggers when the page reloads or changes.&lt;/li&gt;
&lt;li&gt;Drag a &lt;strong&gt;change&lt;/strong&gt; node onto the canvas and set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;global.tasks&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the change setting retriving global context and setting to msg.payload&quot; alt=&quot;&amp;quot;Screenshot of the change setting retriving global context and setting to msg.payload&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-change-node-retriving-global-context-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag a &lt;strong&gt;function&lt;/strong&gt; node onto the canvas and paste the below code into it.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-131&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-131&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Filter the payload array of tasks to include only those tasks associated with the currently logged in user.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Return the modified message object containing the filtered tasks.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-131&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;ui-event&lt;/strong&gt; widget’s output to the &lt;strong&gt;change&lt;/strong&gt; node’s input and the &lt;strong&gt;change&lt;/strong&gt; nodes’ output to the &lt;strong&gt;function&lt;/strong&gt; node’s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;enabling-client-constraint-for-ui-template&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#enabling-client-constraint-for-ui-template&quot;&gt;Enabling client constraint for ui-template&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we begin building our table to display tasks, we need to enable access to client constraints for the &lt;strong&gt;ui-template&lt;/strong&gt; widget. Access client constraints ensure that messages or actions are specifically targeted to individual clients. For instance, if 100 people are interacting with the same task management dashboard simultaneously and one person submits a task, the notification will only be visible to that person and not to the remaining 99 individuals.&lt;/p&gt;
&lt;p&gt;If you have experience with Node-RED Dashboard 1.0, you may recall that these client constraints were only available for &lt;strong&gt;ui-control&lt;/strong&gt; and &lt;strong&gt;ui-notification&lt;/strong&gt; widgets but in Dashboard 2.0 you can enable it for any widget.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying FF Auth tab&quot; alt=&quot;&amp;quot;Screenshot displaying FF Auth tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-2-ff-auth-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the Dashboard 2.0 sidebar and select the top-right &amp;quot;FF Auth&amp;quot; Tab&lt;/li&gt;
&lt;li&gt;In the &amp;quot;Accept Client Constraints&amp;quot; option, you&#39;ll see Dashboard 2.0 widgets where this option is by default enabled for &lt;strong&gt;ui-notification&lt;/strong&gt; and &lt;strong&gt;ui-control&lt;/strong&gt;, enable it for &lt;strong&gt;ui-template&lt;/strong&gt; as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;creating-a-table-and-displaying-the-task&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#creating-a-table-and-displaying-the-task&quot;&gt;Creating a table and displaying the task&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this section, we will build an interactive table using &lt;strong&gt;ui-template&lt;/strong&gt; and &lt;a href=&quot;https://vuetifyjs.com/en/components/all/&quot;&gt;vuetify component&lt;/a&gt;. Vuetify offers a wide range of components, all of which are compatible with our Node-RED Dashboard 2.0&#39;s ui-template widget. You can easily use them by just simply copying and pasting them into the &lt;strong&gt;ui-template&lt;/strong&gt; widget.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an &lt;strong&gt;ui-template&lt;/strong&gt; widget onto the canvas&lt;/li&gt;
&lt;li&gt;Create a new &lt;strong&gt;ui-page&lt;/strong&gt; and &lt;strong&gt;ui-group&lt;/strong&gt; for it. Below, I have provided a screenshot of the &amp;quot;new task&amp;quot; page configurations. Again You can replicate it if you want to align with the layout described in this guide, otherwise, it is optional.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying ui-template widget with code for building table for displaying task&quot; alt=&quot;&amp;quot;Screenshot displaying ui-template widget with code for building table for displaying task&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-template-widget.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Paste the below code into the widget, If you&#39;re new to Vue.js, rest assured I&#39;ve included helpful comments for clarity.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-191&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-191&quot; class=&quot;language-html&quot;&gt;` &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Input field for searching tasks --&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-text-field&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-model&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;prepend-inner-icon&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mdi-magnify&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;single-line&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;outlined&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;hide-details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-text-field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Data table to display tasks --&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-data-table&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:search&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:items&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg?.payload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Custom header for the &quot;current&quot; column --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;header.current&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text-center&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Center-Aligned&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Template for the &quot;priority&quot; column --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;item.priority&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Display priority icon if it exists --&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-icon&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item.priority&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mdi-alert&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;red&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Template for the &quot;user&quot; column --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;item.user&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Display user avatar and username --&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- User avatar --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item.user.image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Username --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ item.user.username }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Template for the &quot;due&quot; column --&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;v-slot:&lt;/span&gt;item.due&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{ item }&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Calculate and display the number of days between due date and current date --&gt;&lt;/span&gt;&lt;br /&gt;   {{ daysBetween(item.due, new Date()) }} Days&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-data-table&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Search input field model&lt;/span&gt;&lt;br /&gt;    search&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  methods&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to calculate the number of days between two dates&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;daysBetween&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;date1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Calculate the difference in days&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; oneDay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// hours*minutes*seconds*milliseconds&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; firstDate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; secondDate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; diffDays &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;firstDate &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; secondDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; oneDay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; diffDays&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;/* Styling for user avatar and username */&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;.user&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  display&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  gap&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Gap between avatar and username */&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;/* Styling for user avatar */&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;.user img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  width&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* Set width of user avatar */&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-191&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the &lt;strong&gt;ui-template&lt;/strong&gt; widget&#39;s input to the &lt;strong&gt;function&lt;/strong&gt; node&#39;s output ( function node which we have added to filter tasks based on user ).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#deploying-the-flow&quot;&gt;Deploying the flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying Node-RED flow of Task management system&quot; alt=&quot;&amp;quot;Screenshot displaying Node-RED flow of Task management system&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-an-application-with-dashboard-task-management-application-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deploy the flow by clicking the top right Deploy button.&lt;/li&gt;
&lt;li&gt;Locate the &#39;Open Dashboard&#39; button at the top-right corner of the Dashboard 2.0 sidebar and click on it to navigate to the dashboard.&lt;/li&gt;
&lt;li&gt;Login with the registered FlowFuse account username and password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, we&#39;re all set to add tasks. Navigate to the &amp;quot;New Task&amp;quot; page to add tasks. To view tasks, navigate to the &amp;quot;your Task&amp;quot; page.&lt;/p&gt;
&lt;h2 id=&quot;next-step&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/how-to-build-an-application-with-node-red-dashboard-2/#next-step&quot;&gt;Next step&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to enhance this simple application by adding more features, consider the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;Webinar&lt;/a&gt; - This webinar provides an in-depth discussion of the Personalised Multi-User Dashboards feature and offers guidance on how to get started with it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/&quot;&gt;Displaying logged-in users on Dashboard 2.0&lt;/a&gt; - This detailed guide demonstrates how to display logged-in users on Dashboard 2.0 which using the FlowFuse Multiuser addon and FlowFuse.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/&quot;&gt;How to Build an Admin Dashboard with Node-RED Dashboard 2.0&lt;/a&gt; - This detailed guide demonstrates how to build a secure admin page in Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blueprints/flowfuse-dashboard/multi-user-dashboard/&quot;&gt;Multi-User Dashboard for Ticket/Task Management&lt;/a&gt; blueprint, which allows you to utilize templates to develop a personalized multi-user dashboard quickly. This Task management blueprint has all features such as adding, updating, and deleting tasks, user profiles, and admin dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/flowfuse-dedicated/</id>
        <title>Introducing FlowFuse Dedicated</title>
        <summary>The Next Level in Node-RED Solutions</summary>
        <updated>2024-04-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/flowfuse-dedicated/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Today, we are excited to officially announce FlowFuse Dedicated, a new way to use our enterprise platform as a single-tenant SaaS offering. This new offering provides all of the benefits of FlowFuse enterprise, with an added focus on data residency, isolation, and private networking to meet compliance needs.&lt;/p&gt;
&lt;p&gt;At FlowFuse, we cater to a diverse spectrum of clients, ranging from burgeoning startups to formidable global enterprises. It&#39;s clear that a one-size-fits-all approach to deployment doesn&#39;t align with the varied needs of our customer base. FlowFuse&#39;s product already has flexible deployment options, ranging from FlowFuse Cloud, to a cloud environment of your choosing, to your own hardware on-premise. Allowing our customers to achieve compliance even in the stringent regulatory frameworks. Even sectors not traditionally bound by stringent regulatory frameworks are finding compliance to be a critical factor impacting productivity and profitability.&lt;/p&gt;
&lt;p&gt;Here’s what sets FlowFuse Dedicated apart:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single-Tenant FlowFuse Platform:&lt;/strong&gt; Enjoy the exclusivity of a dedicated environment, ensuring that your operations are isolated, secure, and tailored to your specific needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SaaS-like Efficiency:&lt;/strong&gt; Experience the ease and simplicity of a SaaS solution, where FlowFuse takes care of the entire management and deployment process. When software is not upgraded to the latest versions, organizations use obsolete and inefficient software that can be exposed to security threats. Because FlowFuse Dedicated is fully managed by FlowFuse, customers get access to the latest software features and security updates imminently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regional Deployment Flexibility:&lt;/strong&gt; FlowFuse Dedicated can be deployed in the region of your choice, ensuring data residency requirements are met while optimizing performance by reducing latency. FlowFuse Dedicated can be deployed in 30+ regions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise-Grade Features:&lt;/strong&gt; Enjoy access to all enterprise features and configurations as your own FlowFuse Administrator, enabling you to manage multiple teams effectively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive Compliance:&lt;/strong&gt; Meet complex compliance standards with ease, thanks to full data and source code IP isolation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse Dedicated represents a paradigm shift in Node-RED offerings, a solution that not only meets the demanding requirements of today&#39;s enterprises in terms of speed, efficiency, and productivity but also navigates the complex terrain of compliance and data security with unparalleled finesse. &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;Contact us to learn more&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/</id>
        <title>FlowFuse Gears Up for Hannover Messe</title>
        <summary>Meet the team behind FlowFuse and contributors to Node-RED</summary>
        <updated>2024-04-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;We&#39;re excited to announce that FlowFuse will be exhibiting at the upcoming Hannover Messe! This renowned industrial trade fair provides a platform to connect with global innovators and explore the latest advancements.  Visit us in Hall 14, Stand L59 from April 22nd - 26th.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you need a pass?  We can help with that as well.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;understanding-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#understanding-node-red&quot;&gt;Understanding Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED, created by our co-founder Nick O&#39;Leary, is a powerful open-source tool that makes it easy to connect industrial devices, collect data, and create insightful visualizations. Its intuitive interface and wide range of integrations have made it a popular choice in manufacturing.&lt;/p&gt;
&lt;h2 id=&quot;scaling-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#scaling-with-flowfuse&quot;&gt;Scaling with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As organizations adopt Node-RED more extensively, managing multiple instances can become complex. FlowFuse addresses this by providing a central platform designed to streamline Node-RED operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Operations and Maintenance: Get a consolidated view of your Node-RED instances, track their health, and ensure smooth operation.&lt;/li&gt;
&lt;li&gt;Developer Velocity: Enhance development efficiency with streamlined updates, remote access, and version control for Node-RED deployments.&lt;/li&gt;
&lt;li&gt;Security and Compliance: Integrate Node-RED with your existing security systems, implement detailed user permissions, and maintain audit logs to satisfy industry regulations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;experience-flowfuse-at-hannover-messe&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#experience-flowfuse-at-hannover-messe&quot;&gt;Experience FlowFuse at Hannover Messe&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;come-see-us-at-our-booth-for%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#come-see-us-at-our-booth-for%3A&quot;&gt;Come see us at our booth for:&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Live demonstrations showcasing how FlowFuse enhances your Node-RED applications.&lt;/li&gt;
&lt;li&gt;Discussions about tackling common challenges in industrial data management.&lt;/li&gt;
&lt;li&gt;A chance to connect with our team and learn how we can support your goals.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;let&#39;s-connect!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#let&#39;s-connect!&quot;&gt;Let&#39;s Connect!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in making the most of Node-RED within your manufacturing processes, FlowFuse offers the tools to simplify and secure your operations. Stop by our booth at Hannover Messe!&lt;/p&gt;
&lt;h2 id=&quot;get-your-free-pass-to-hannover-messe&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/flowfuse-at-hannover-messe-node-red/#get-your-free-pass-to-hannover-messe&quot;&gt;Get Your Free Pass to Hannover Messe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Interested in attending Hannover Messe? Click &lt;a href=&quot;https://www.hannovermesse.de/en/application/registration/direct-entry-tickets-passes?code=hXWhs&quot;&gt;here&lt;/a&gt; to claim your free pass to the event.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/node-red-multiplayer/</id>
        <title>Node-RED Multiplayer mode</title>
        <summary>An update on our work to bring concurrent editing to Node-RED</summary>
        <updated>2024-04-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/node-red-multiplayer/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Last month I &lt;a href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/&quot;&gt;wrote&lt;/a&gt; about what users
can expect with Node-RED 4.0. One of the features I highlighted was improving the
concurrent editing experience. With the recent &lt;a href=&quot;https://discourse.nodered.org/t/node-red-4-0-0-beta-2-released/87026&quot;&gt;beta release&lt;/a&gt; of Node-RED, the first
steps on that journey are now available to try.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;ll cover what has been done so far and what we&#39;ve got planned.&lt;/p&gt;
&lt;p&gt;Full concurrent editing within Node-RED is not a small task, so naturally we&#39;re breaking it up into a series of iterations that each bring us a step closer to the eventual goal.&lt;/p&gt;
&lt;p&gt;The natural first step was to add some basic awareness of who else has the editor open. On the surface, this may sound like a simple step, but it required laying lots of groundwork to achieve such as designing how the editor and runtime communicate this state in real-time.&lt;/p&gt;
&lt;p&gt;It also meant starting to figure out the visual language we&#39;ll use in the editor to represent users. I spent time researching how other applications handle this - seeing what would work in the Node-RED context.&lt;/p&gt;
&lt;p&gt;With Node-RED v4-beta.2, we have made these first steps available to the community. When the feature is enabled, you will now see icons in the header for all of the other users that have the editor open.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot of Node-RED with additional user icons in the header&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr-multiplayer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot of Node-RED with additional user icons in the header&lt;/figcaption&gt;
&lt;p&gt;Clicking on their icon will show a little information box about &lt;em&gt;where&lt;/em&gt; they are in the editor. Now, for this iteration, that information is fairly crude - it will tell you the name of the flow they have open and which node they are currently editing, but that&#39;s it. Which leads me on to what we have planned next.&lt;/p&gt;
&lt;h3 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-multiplayer/#next-steps&quot;&gt;Next steps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next iteration will be to improve how we indicate where a user is in the editor. Adding mini-icons to the editor tabs, or as annotations on individual nodes will allow us to more seamlessly indicate where a user is.&lt;/p&gt;
&lt;p&gt;After that, one possible option will be to show the user&#39;s mouse cursor movement in real-time within the flow tab, and start to layer up the feedback we can provide as they make changes.&lt;/p&gt;
&lt;h3 id=&quot;trying-it-out-on-flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-multiplayer/#trying-it-out-on-flowfuse-cloud&quot;&gt;Trying it out on FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I mentioned earlier this feature has to be enabled. For a local install, details on how to do this are in the &lt;a href=&quot;https://discourse.nodered.org/t/node-red-4-0-0-beta-2-released/87026#introducing-multiplayer-mode-2&quot;&gt;release forum post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to give it a go now, we already have Node-RED v4-beta.2 available to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;try on FlowFuse Cloud&lt;/a&gt; - where the multiplayer feature is pre-enabled whilst it&#39;s in beta mode.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/</id>
        <title>How to Build an Admin Dashboard with Node-RED Dashboard 2.0</title>
        <summary>A guide to building an Admin Dashboard in Node-RED with Dashboard 2.0</summary>
        <updated>2024-04-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Managing and analyzing increasing amounts of data becomes crucial for organizations. Dashboard 2.0 and Node-RED help organizations access the data, normalize it, and visualize it. But what about controlling who can access what data? That&#39;s where an admin-only page comes in. Now With Node-RED Dashboard 2.0, we can also create robust and secure admin-only pages easily. In this guide, we&#39;ll provide you with step-by-step instructions to Build an Admin-only page with Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;If you&#39;re new to Dashboard 2.0, refer to our blog post &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard 2.0&lt;/a&gt; to install and get things started.&lt;/p&gt;
&lt;h2 id=&quot;enabling-flowfuse-user-authentication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#enabling-flowfuse-user-authentication&quot;&gt;Enabling FlowFuse User Authentication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before proceeding further, let’s enable FlowFuse user authentication. This step adds an extra layer of protection to our dashboard by adding a login page that restricts access exclusively to registered FlowFuse users. Additionally, it further simplifies the process for the FlowFuse Multiuser addon to track and access logged-in user&#39;s data on the dashboard.&lt;/p&gt;
&lt;p&gt;For more information, refer to the &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/#flowfuse-user-authentication&quot;&gt;documentation&lt;/a&gt; and ensure that it is enabled.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.&quot; alt=&quot;&amp;quot;Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.
&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-flowfuse-instance-setting.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;exploring-flowfuse-multiuser-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#exploring-flowfuse-multiuser-addon&quot;&gt;Exploring FlowFuse Multiuser Addon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse Multiuser Addon is a plugin developed for Dashboard 2.0 to access logged-in user data on the dashboard. To install and understand how the FlowFuse Multiuser Addon works, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#enabling-flowfuse-user-authentication&quot;&gt;Exploring the FlowFuse User Addon &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;storing-a-list-of-admin-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#storing-a-list-of-admin-users&quot;&gt;Storing a list of Admin users&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we start building the admin-only page We need to store a list of admin users somewhere so that we can later display the admin-only page to those users only, For this guide we will store the admin list in the global context.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto the canvas.&lt;/li&gt;
&lt;li&gt;Drag the &#39;change&#39; node onto the canvas and set &lt;code&gt;global.admins&lt;/code&gt; to a JSON array containing the usernames of admin users. This will store the created admin list in our Node-RED global context.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node which which stores list of admins username in global context&quot; alt=&quot;&amp;quot;Screenshot displaying the change node which which stores list of admins username in global context&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-change-node-for-storing-adminlist-to-global-contenxt.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Connect the inject node’s output to the change node’s input.&lt;/li&gt;
&lt;li&gt;To store the list in a global context, click the inject node’s button once you&#39;ve deployed the flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;building-an-admin-only-page&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#building-an-admin-only-page&quot;&gt;Building an Admin-only page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, let&#39;s proceed with the practical steps to implement the admin-only page:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new page in Dashboard 2.0, where we will display sensitive data that we want to hide from regular users, this page will be our admin page.&lt;/li&gt;
&lt;li&gt;Drag an event node on the canvas, then click on it, and select the UI base that contains your all pages including the admin page&lt;/li&gt;
&lt;li&gt;Drag a switch node on the canvas, and add two conditions, one to check whether the user’s username is contained in the admin list or a second for otherwise, see the below image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the switch node which checks whether the logged-in user&#39;s username is contained in the admin list or not&quot; alt=&quot;&amp;quot;Screenshot displaying the switch node which checks whether the logged-in user&#39;s username is contained in the admin list or not&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-switch-node-checking-page-viewer-isadmin.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Drag two change nodes onto the canvas, Configure the first change node to show the admin page by setting &lt;code&gt;msg.payload&lt;/code&gt; as &lt;code&gt;{&amp;quot;pages&amp;quot;:{&amp;quot;show&amp;quot;:[&amp;quot;Admin View&amp;quot;]}}&lt;/code&gt;, and the second change node to hide the admin page by setting the payload as: &lt;code&gt;{&amp;quot;pages&amp;quot;:{&amp;quot;hide&amp;quot;:[&amp;quot;Admin View&amp;quot;]}}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node which contains payload to show admin page&quot; alt=&quot;&amp;quot;Screenshot displaying the change node which contains payload to show admin page&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-change-node-for-showing-page.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the change node which contains payload to display admin page&quot; alt=&quot;&amp;quot;Screenshot displaying the change node which contains payload to hide admin page&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-change-node-for-hidding-page.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Connect the first change node&#39;s input to the switch node&#39;s first output and the second change node&#39;s input to the switch node&#39;s second output.&lt;/li&gt;
&lt;li&gt;Drag a ui-control widget onto the canvas, then click on it and select ui-base which includes all your pages including the admin page.&lt;/li&gt;
&lt;li&gt;Finally, connect both change node’s outputs to the ui-control’s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;hidding-admin-only-page-by-default&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#hidding-admin-only-page-by-default&quot;&gt;Hidding Admin only page by default&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To hide an admin-only page by default to ensure regular users don&#39;t accidentally land on the admin-only page the following steps are needed.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the Dashboard 2.0 sidebar, and select the layout tab.&lt;/li&gt;
&lt;li&gt;Locate the admin-only page and click on the edit icon next to it.&lt;/li&gt;
&lt;li&gt;Set visibility as &amp;quot;hidden&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying admin-only page configuration&quot; alt=&quot;&amp;quot;Screenshot displaying admin-only page configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-admin-only-page-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#deploying-the-flow&quot;&gt;Deploying the flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the FlowFuse Editor with flow of admin-only page&quot; alt=&quot;&amp;quot;Screenshot displaying the FlowFuse Editor with flow of admin-only page&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-flowfuse-editior.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;With your flow updated to include the above, click the &amp;quot;Deploy&amp;quot; button in the top-right of the Node-RED Editor.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When you visit the page for the first time, you&#39;ll need to log in with your FlowFuse username and password or through Single-Sign on.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, if your username is added to the list of admin usernames stored in the global context, you will be able to see the admin-only page.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the Dashboard view of normal users&quot; alt=&quot;&amp;quot;Screenshot displaying the Dashboard view of normal users&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-dashboard-view-for-normal-users.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the Dashboard view of admin users&quot; alt=&quot;&amp;quot;Screenshot displaying the Dashboard view of admin users&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/building-admin-panel-node-red-dashboard-2-dashboard-view-for-admin-users.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;next-step&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/building-an-admin-panel-in-node-red-with-dashboard-2/#next-step&quot;&gt;Next step&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to learn more about FlowFuse multiuser addon and personalize the multiuser dashboard. we do have many other resources, please refer to them to learn more.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;Webinar&lt;/a&gt; - This webinar provides an in-depth discussion of the Personalised Multi-User Dashboards feature and offers guidance on how to get started with it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/&quot;&gt;Personalised Multi-user Dashboards with Node-RED Dashboard 2.0&lt;/a&gt; - This article explores the process of building multi-user Dashboards secured with FlowFuse Cloud.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/&quot;&gt;Displaying logged-in users on Dashboard 2.0&lt;/a&gt; - This detailed guide demonstrates how to display logged-in users on Dashboard 2.0 which using the FlowFuse Multiuser addon and FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blueprints/flowfuse-dashboard/multi-user-dashboard/&quot;&gt;Multi-User Dashboard for Ticket/Task Management&lt;/a&gt; blueprint, which allows you to utilize templates to develop Personalize multi-user dashboard quickly.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/</id>
        <title>Role-Based Access for your Node-RED applications</title>
        <summary>Collaboration and Security in Node-RED with Role-Based Access Control with FlowFuse.</summary>
        <updated>2024-04-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Role-based access Control (RBAC) is a crucial component of modern software platforms. It provides granular control over access rights and enhances security. Integrating RBAC into the FlowFuse platform brings this level of sophistication to Node-RED, allowing users to manage their environments with precision and confidence. This blog will explore how FlowFuse&#39;s RBAC system improves both security and user experience within the Node-RED ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;roles-overview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/#roles-overview&quot;&gt;Roles Overview&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse offers a variety of roles that cater to different levels of access within the Node-RED environment, ensuring that users can tailor their platform according to their needs. These roles include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Owner - The highest level of access with full control over team settings, instances, and features.&lt;/li&gt;
&lt;li&gt;Member - Functions similarly to Owner, but inhibits the abilities to change instance states and manage members.&lt;/li&gt;
&lt;li&gt;Viewer - Allows users to visualize and see flows and dashboards.  This is great for collaboration across multi tenant teams.&lt;/li&gt;
&lt;li&gt;Dashboard Only - Designed for end users that will interact with Dashboards, but don&#39;t have a reason to see or edit flows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Role Based Access Control For Node-RED with FlowFuse&quot; alt=&quot;&amp;quot;Role Based Access Control For Node-RED with FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/role-based-access-control-for-node-red-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For further details see &lt;a href=&quot;https://flowfuse.com/docs/user/team/#role-based-access-control&quot;&gt;documentation&lt;/a&gt; for full granularity of roles.&lt;/p&gt;
&lt;h2 id=&quot;instance-protection-mode&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/#instance-protection-mode&quot;&gt;Instance Protection Mode&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A useful feature of FlowFuse&#39;s RBAC system is the Instance Protection Mode. This mode adds an additional layer of security by locking down critical Node-RED instances, preventing unauthorized modifications to configuration and nodes. The protection mode is particularly useful in production environments and areas in which need an extra layer of protection for any unintentional updates or changes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Protect Node-RED instance from change with Instance Protection Mode&quot; alt=&quot;&amp;quot;Protect Node-RED instance from change with Instance Protection Mode&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/protect-instance-node-red-with-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-impact-on-user-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/#the-impact-on-user-experience&quot;&gt;The Impact on User Experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse&#39;s RBAC system significantly enhances the user experience for Node-RED users by providing a secure, customizable, and controlled environment. Teams can collaborate more efficiently and safely, knowing that access is properly managed and critical systems are protected.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse&#39;s integration of RBAC into the Node-RED ecosystem represents a significant enhancement in how users can interact with, manage, and secure their Node-RED instances. By offering detailed control over access rights and introducing features like Instance Protection Mode, FlowFuse not only secures Node-RED environments but also greatly improves their manageability and the overall user experience. With RBAC, users can now tailor their Node-RED platforms according to their specific needs while ensuring that security and collaboration are at the forefront of their operations.&lt;/p&gt;
&lt;p&gt;For more information on how to implement and utilize Role-Based Access Control within FlowFuse, please refer to our &lt;a href=&quot;https://flowfuse.com/docs/user/team/#role-based-access-control&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/</id>
        <title>Displaying logged in user on Node-RED Dashboard 2.0</title>
        <summary>Step-by-Step Beginner&#39;s Guide to Displaying logged in User on Node-RED Dashboard 2.0</summary>
        <updated>2024-04-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;About a month ago, a powerful solution became available to the Node-RED community to deal with users and allow multiple to interact with the same dashboard in a personalized manner. It&#39;s called the  Multli user Dashboard for Node-RED. In this guide, we will provide a step-by-step guide to show you how to secure your dashboard and access and display logged in user information on Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;If you&#39;re new to Dashboard 2.0, refer to our blog post &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting Started with Dashboard 2.0&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;enabling-flowfuse-user-authentication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#enabling-flowfuse-user-authentication&quot;&gt;Enabling FlowFuse User Authentication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we display logged-in user data on the dashboard, first we need to set up a login mechanism with FlowFuse for the dashboard. This simplifies securing Node-RED Dashboards and provides contextual user data within the Dashboard itself for who is logged in.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the Instance &amp;quot;settings&amp;quot;.&lt;/li&gt;
&lt;li&gt;Select the &amp;quot;Security&amp;quot; tab.&lt;/li&gt;
&lt;li&gt;Enable “FlowFuse User Authentication”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, the first time you visit the dashboard, you&#39;ll need to log in with your registered FlowFuse username and password&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.&quot; alt=&quot;&amp;quot;Screenshot displaying the configuration settings within the FlowFuse instance, enabling user authentication for enhanced security.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/displaying-logged-in-user-flowfuse-instance-setting.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;exploring-the-flowfuse-user-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#exploring-the-flowfuse-user-addon&quot;&gt;Exploring the FlowFuse User Addon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse User Addon is a plugin developed for Dashboard 2.0, leveraging the FlowFuse API to retrieve information about logged in user.&lt;/p&gt;
&lt;h3 id=&quot;installing-flowfuse-user-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#installing-flowfuse-user-addon&quot;&gt;Installing Flowfuse user addon&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Click the Node-RED Settings (top-right)&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Manage Palette&amp;quot;&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Install&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;@flowfuse/node-red-dashboard-2-user-addon&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#how-it-works&quot;&gt;How it Works&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this addon, user information is attached to the &lt;code&gt;msg&lt;/code&gt; emitted by Dashboard 2.0 nodes. This user information object is attached as &lt;code&gt;msg._client.user&lt;/code&gt;. Below is an example of how that object looks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
   &amp;quot;userId&amp;quot;: &amp;quot;&amp;quot;, // unique identifier for the user
   &amp;quot;username&amp;quot;: &amp;quot;&amp;quot;, // FlowFuse Username
   &amp;quot;email&amp;quot;: &amp;quot;&amp;quot;, // E-Mail Address connected to their FlowFuse account
   &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;, // Full Name
   &amp;quot;image&amp;quot;: &amp;quot;&amp;quot; // User Avatar from FlowFuse
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Behind the scenes, the user addon is appending the user object to the &lt;code&gt;msg&lt;/code&gt;, via the SocketIO auth option. We make the socketio object available via a computed &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/guides/state-management.html#setup-store&quot;&gt;setup&lt;/a&gt; object, this means that we can also access user data in any ui-template widget with ``, in the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;, or &lt;code&gt;this.setup.socketio.auth.user&lt;/code&gt;, in the JS.&lt;/p&gt;
&lt;p&gt;When running Node-RED Dashboard 2.0 on FlowFuse, you&#39;ll have a new tab available in the &amp;quot;Dashboard 2.0&amp;quot; sidebar in the Node-RED Editor, you just have to navigate to the &amp;quot;FF Auth&amp;quot; tab and you’ll see two options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1: Include Client Data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By default, this option is enabled. When this option is enabled, an object with user information will be added to the “msg” emitted by any widget of the Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 2: Accept Client Constraints&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A feature that ensures messages are specifically targeted to individual clients, which enhances the precision and security of data transmission within the platform. It determines by enabling the nodes option in the FF Auth tab whether the enabled node type will utilize client data, such as socketid, and restrict communications to only that client.&lt;/p&gt;
&lt;p&gt;For example, consider a manufacturing facility where each production line has its own monitoring system. With this feature enabled, data from sensors on Production Line A will only be sent to the monitoring system designated for Production Line A. This ensures that data remains isolated and relevant to each specific area of operation, maintaining organizational efficiency and security.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Please note that Multi-User Addons can only be used by our Teams and Enterprise Self-Hosted customers. Upon request, we provide all required configurations to get started.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot displaying the FlowFuse Muti-user addon option&quot; alt=&quot;&amp;quot;Screenshot displaying the FlowFuse Muti-user addon option&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/displaying-logged-in-user-ff-auth-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;displaying-logged-in-user-on-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#displaying-logged-in-user-on-dashboard-2.0&quot;&gt;Displaying logged in user on Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now you know how the user add on works, you are all set to display logged in users on Dashboard 2.0. To confirm this you can use a &lt;code&gt;debug&lt;/code&gt; node that receives the &lt;code&gt;msg&lt;/code&gt; object emitted by the Dashboard 2.0 widgets.&lt;/p&gt;
&lt;p&gt;To display user information on the dashboard we will use Vue’s &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#teleports&quot;&gt;Teleport&lt;/a&gt; feature to render content to a specific location in the DOM, we will display user information at the action bar’s right-hand side.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a &lt;code&gt;ui-template&lt;/code&gt; widget onto the canvas.&lt;/li&gt;
&lt;li&gt;Click on that node, and select type as “Widget (Ui-Scoped)”. ( this allows us to render this ui-template at ui scoped which means I will not required to add separate ui-templates for different pages )&lt;/li&gt;
&lt;li&gt;Copy the below vue snippet and paste that into the ui-template.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-131&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-131&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Teleporting user info to #app-bar-actions, which is the ID of the action bars&#39; right corners area --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Teleport&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;loaded&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#app-bar-actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;user-info&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Displaying user image --&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;setup.socketio.auth.user.image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Greeting the user --&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hi, {{ setup.socketio.auth.user.name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Teleport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Flag to indicate if the component is loaded&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// This function is called when the component is inserted into the DOM.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Setting loaded to true here ensures the component is ready to access #app-bar-actions,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// as it&#39;s now part of the same DOM structure.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Accessing it before mounted() would cause an error because the component wouldn&#39;t be initialized in the DOM yet.&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loaded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Setting loaded to true to indicate that the component has been mounted successfully&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Styling for user info display */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.user-info&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;gap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Styling for user avatar image*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.user-info img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-131&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#deploying-the-flow&quot;&gt;Deploying the flow&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;With your flow updated to include the above, click the &amp;quot;Deploy&amp;quot; button in the top-right of the Node-RED Editor.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of Dashboard displaying logged in user information&quot; alt=&quot;&amp;quot;Screenshot of Dashboard displaying logged in user information&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/displaying-logged-in-user-dashboard-view.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;next-step&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#next-step&quot;&gt;Next step&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to learn more about the FlowFuse Multiuser addon and Personalize Multiuser Dashboard. we do have many other resources, please refer to them to learn more.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;Webinar&lt;/a&gt; - This webinar provides an in-depth discussion of the Personalised Multi-User Dashboards feature and offers guidance on how to get started with it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/&quot;&gt;Personalised Multi-user Dashboards with Node-RED Dashboard 2.0&lt;/a&gt; - This article explores the process of building multi-user Dashboards secured with FlowFuse Cloud.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blueprints/flowfuse-dashboard/multi-user-dashboard/&quot;&gt;Multi-User Dashboard for Ticket/Task Management&lt;/a&gt; blueprint, which allows you to quickly utilize templates to develope Personalize multi-user dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/displaying-logged-in-users-on-dashboard/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we have demonstrated how to secure your dashboard and how to retrieve and display logged in user data on Dashboard 2.0. Additionally, we have discussed the functionality of the FlowFuse multi-user addon.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/04/node-red-architecture/</id>
        <title>Node-RED Manufacturing Architecture</title>
        <summary>Enhancing Factory Operations with Node-RED and FlowFuse</summary>
        <updated>2024-04-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/04/node-red-architecture/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The architecture of a factory&#39;s Node-RED infrastructure is a common topic of discussion and inquiry. Fundamentally, my response to such queries unfolds in two parts. Initially, the focus must be on data organization. I champion a structure centered around a &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace&lt;/a&gt;, a concept I explore in depth in this article &lt;a href=&quot;https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/&quot;&gt;&amp;quot;Node-RED in a Unified Namespace Architecture.&amp;quot;&lt;/a&gt; However, this is only one part of the inquiry. The other part of the question delves into the positioning of FlowFuse and Node-RED within the network infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-multilayered-approach%3A-the-foundation-of-factory-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-architecture/#understanding-the-multilayered-approach%3A-the-foundation-of-factory-architecture&quot;&gt;Understanding the Multilayered Approach: The Foundation of Factory Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For illustrative purposes, I’ve opted to reference the &lt;a href=&quot;https://webstore.ansi.org/preview-pages/ISA/preview_S_990001_2007.pdf&quot;&gt;Purdue / ISA-99 Model&lt;/a&gt;, despite its fair share of criticism. Many of today&#39;s factories and manufacturing spaces adhere to this model, and the aim here is to mirror a realistic network scenario. For the sake of clarity, I&#39;ve condensed the network into three primary layers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ISA-99 Visualization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Purdue Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/purdue-model.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;At the base is the Shopfloor layer. This is where all the physical factory equipment resides. Often, this layer is segmented further, but for our discussion, it&#39;s represented as a single zone.&lt;/p&gt;
&lt;p&gt;Next is the Edge layer, which serves as the communicative conduit between the Shopfloor and the Enterprise layers. This layer often contains a Demilitarized Zone (DMZ) where various Gateways are positioned.&lt;/p&gt;
&lt;p&gt;At the top, we find the Enterprise Layer. This can signify either cloud services or a company-wide accessible network. Frequently, the Cloud and Enterprise layers are divided, but in our case, it doesn’t matter whether they are separated.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Node-RED Manufacturing Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-architecture.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;applications-across-factory-layers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-architecture/#applications-across-factory-layers&quot;&gt;Applications Across Factory Layers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Shopfloor:&lt;/strong&gt; Node-RED&#39;s versatility shines at the shopfloor level, where it’s typically installed on a variety of industrial devices. A prominent application is the development of simple Human-Machine Interfaces (HMIs) using the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Dashboard module&lt;/a&gt;, which enables operators to interact with the machines visually and intuitively. Additionally, Node-RED is instrumental in data acquisition tasks, where it can gather, process, and interpret data from sensors and actuators in real-time. This capability allows for the monitoring of production processes, predictive maintenance, and the triggering of automated workflows in response to specific conditions or anomalies detected on the shop floor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edge:&lt;/strong&gt; At the edge level, Node-RED plays a pivotal role in harmonizing the divide between Operational Technology (OT) and Information Technology (IT). Its gateway functionalities are not only integral in facilitating the flow of data between the shopfloor devices and the enterprise-level systems but also it is at this juncture that plant-wide Key Performance Indicators (KPIs) are generated. These KPIs, aggregated from various data points across the production line, are essential for operational oversight and strategic decision-making. Edge-level Node-RED instances can run local analytics and manage alarms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enterprise Network:&lt;/strong&gt; Within the higher echelons of the network, FlowFuse establishes its domain, serving as a central hub for managing multiple Node-RED instances. In this space, Node-RED’s agility is leveraged for creating test environments, where simulated data flows can be used to model and understand potential changes before they are deployed on the shopfloor. For enterprise-wide KPI calculations, advanced analytics, and integration with other business systems like ERP or CRM. This layer can use data processed at the edge to inform enterprise-level decisions, drive continuous improvement, and harness machine learning models to glean deeper insights into the production process, quality control, and supply chain logistics.&lt;/p&gt;
&lt;h3 id=&quot;the-device-agent%3A-empowering-remote-node-red-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-architecture/#the-device-agent%3A-empowering-remote-node-red-instances&quot;&gt;The Device Agent: Empowering Remote Node-RED Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every Node-RED instance that isn’t hosted within the Enterprise/Cloud Network’s domain of FlowFuse operates on a Device Agent. This simple tool runs Node-RED and facilitates the connection to FlowFuse. Such remote Node-RED instances are referred to as Devices.&lt;/p&gt;
&lt;h3 id=&quot;how-to-communicate-between-node-red-instance%3F-project-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-architecture/#how-to-communicate-between-node-red-instance%3F-project-nodes&quot;&gt;How to communicate between Node-RED Instance? Project Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Facilitating communication between Node-RED instances is a fundamental requirement for creating a cohesive and responsive Node-RED architecture. FlowFuse elevates this capability by providing an event-driven communication framework (based on MQTT) that binds different Node-RED instances together. This is primarily achieved through the use of Project Links—a feature within FlowFuse that allows for the smooth transfer of data between instances.&lt;/p&gt;
&lt;p&gt;These &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;Project Links&lt;/a&gt; are more than just communication channels; they represent a method of organizing Node-RED instances into a networked application, where each instance can be considered a node within the project. With Project Links, instances can subscribe to specific events or topics and publish messages that other instances are listening for. This is particularly useful for triggering actions across the network, like updating a dashboard in real time or controlling devices on the shopfloor based on analytics computed at the edge.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/04/node-red-architecture/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By employing a unified namespace approach and strategically positioning Node-RED and FlowFuse within the network, we enable a seamless flow of data from the shopfloor to the enterprise level. This multilayered approach not only enhances communication between operational technology and information technology but also empowers real-time monitoring, predictive maintenance, and strategic decision-making.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/</id>
        <title>Using Kafka with Node-RED</title>
        <summary>Step-by-step Guide to Using Kafka with Node-RED for sending and receiving data.</summary>
        <updated>2024-03-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Kafka is one of the most powerful technologies enabling seamless data communication. Many individuals are utilizing it alongside Node-RED for real-time data exchange in their IoT and IIoT applications. However, some users are encountering difficulties in obtaining assistance with Kafka-related queries.&lt;/p&gt;
&lt;p&gt;During my recent visit to the Node-RED Forum, I noticed that while some Kafka-related queries have been answered nicely, others remain unanswered or have not been satisfactorily addressed, leaving users feeling stuck. To address this issue, we&#39;ve created a comprehensive Kafka guide covering everything you need to know about Kafka, from installation and connection to data transmission. For newcomers to Kafka, we recommend reading our previous blog on &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/&quot;&gt;how Kafka is applied in manufacturing&lt;/a&gt;, where we&#39;ve covered the basics and practical applications extensively.&lt;/p&gt;
&lt;h2 id=&quot;discussing-problem-and-potential-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#discussing-problem-and-potential-solution&quot;&gt;Discussing problem and potential solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s start by discussing a problem: imagine a temperature sensor network across a city. We need to centralize and analyze this data in real time for effective monitoring and visualization.&lt;/p&gt;
&lt;p&gt;To resolve this problem we will use Kafka, Temperature sensors will feed data into Kafka through the Kafka producer. To retrieve real-time data for visualization and monitoring, we’ll be using Kafka Consumer. We will organize the data by region. The temperature data for each region will be managed in a specific Kafka topic partition.&lt;/p&gt;
&lt;p&gt;While in this guide, we will generate simulated data using random number expression and run both producers and consumers on the same system, practical scenarios often involve distributed setups across different devices or systems.&lt;/p&gt;
&lt;h2 id=&quot;installing-and-running-kafka-locally&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#installing-and-running-kafka-locally&quot;&gt;Installing and running Kafka locally&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this part, we’ll be installing Kafka locally using Docker to simplify the installation process, so make sure you’ve got Docker installed before you dive in.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pull the zookeeper image if it is not already, and run the zookeeper container.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker run -p 2181:2181 zookeeper
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Pull the Kafka image if it is not already, and run Kafka Container, expose PORT 9092.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker run -p 9092:9092 `
-e KAFKA_ZOOKEEPER_CONNECT=&amp;lt;Your_Private_Ip&amp;gt;.1:2181 `
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://&amp;lt;Your_Private_Ip&amp;gt;:9092 `
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 `
confluentinc/cp-kafka
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;running-kafka-on-the-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#running-kafka-on-the-cloud&quot;&gt;Running Kafka on the cloud&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To run Kafka on the cloud, you can consider utilizing any cloud service according to your preferences. For a guide on running Kafka on a cloud platform, the procedures may differ. You can refer to the documentation provided by your preferred cloud service for detailed instructions.&lt;/p&gt;
&lt;p&gt;During the writing of this tutorial, I utilized &lt;a href=&quot;https://aiven.io/kafka-connect&quot;&gt;Aiven’s cloud data platform&lt;/a&gt; which offers the option to use Kafka in the free trial. However, you are free to choose any cloud service that suits your requirements and preferences.&lt;/p&gt;
&lt;h2 id=&quot;installing-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#installing-dashboard-2.0&quot;&gt;Installing Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We will be installing Dashboard 2.0 to display real-time temperature data of various regions on a chart. If you are new to Dashboard 2.0, we recommend referring to &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting started with Dashboard 2.0&lt;/a&gt;, which covers everything from basic concepts to installation and creating your first dashboard seamlessly.&lt;/p&gt;
&lt;h2 id=&quot;installing-and-configuring-kafka-custom-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#installing-and-configuring-kafka-custom-node&quot;&gt;Installing and configuring Kafka custom node&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;node-red-kafka-manager&lt;/code&gt; by the palette manager.&lt;/li&gt;
&lt;li&gt;Before connecting to Kafka, ensure you have the following information ready and environment variables set up as discussed below in the Adding environment variable section.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Host: The IP address or hostname of your Kafka broker server.&lt;/li&gt;
&lt;li&gt;Port: Kafka typically uses port 9092 by default. Ensure this aligns with your Kafka broker&#39;s configuration.&lt;/li&gt;
&lt;li&gt;SSL Configuration (if applicable):
CA Certificate: The Certificate Authority (CA) certificate for validating the SSL connection.&lt;/li&gt;
&lt;li&gt;SASL (Simple Authentication and Security Layer) Mechanism: Most of the Kafka broker servers use SASL for authentication such as &#39;PLAIN&#39;, &#39;SCRAM-SHA-256,&#39; or &#39;SCRAM-SHA-512.&#39;&lt;/li&gt;
&lt;li&gt;Username: SASL username of Kafka broker server for authentication.&lt;/li&gt;
&lt;li&gt;Password: SASL password of Kafka broker server for authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Drag the Kafka Producer node onto the Canvas, click on that node, and click on the edit icon next to the broker input field to configure it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing configuration of kafka&quot; alt=&quot;&amp;quot;Screenshot showing configuration of kafka&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-kafka-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Enable the TLS option if your Kafka broker server is using it for secure communication.&lt;/li&gt;
&lt;li&gt;After enabling the TLS option click on the edit icon next to &lt;code&gt;add new tls-config&lt;/code&gt; and upload the CA Certificate in PEM format.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Configuring tls for kafka&quot; alt=&quot;&amp;quot;Screenshot showing TLS configuration for kafka&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-tls-configuration.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;adding-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#adding-environment-variables&quot;&gt;Adding Environment variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will be setting up environment variables for Kafka configuration. If you have read our previous blog post, you may already know why we highly suggest using environment variables for every configuration. If not, please refer to our blog post on &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing adding environment variable in Node-RED&quot; alt=&quot;&amp;quot;Screenshot showing adding environment variable in Node-RED&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-setting-environment-variables.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the instance&#39;s setting and then go to the environment section.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;add variable&lt;/code&gt; button and add variables ( host, port, username, and password) for the configuration data that we discussed in the above section. To leverage the ease of configuration provided by the Kafka custom node that we are utilizing, ensure to set only one variable for both host and port in the following format:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;[{&amp;quot;host&amp;quot;:&amp;lt;enter IP address or hostname of your Kafka broker server &amp;gt;,&amp;quot;port&amp;quot;:&amp;lt;enter port on which your kafka broker server is listening&amp;gt;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Click on the save button and restart the instance by clicking on the top right Action button and selecting the restart option.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;creating-a-new-kafka-topic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#creating-a-new-kafka-topic&quot;&gt;Creating a new Kafka topic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we&#39;ll guide you through the process of creating a Kafka topic to handle temperature data from different city regions. To ensure the segregation of data for different zones within the city, we will configure the topic to create three partitions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag an inject node onto Canvas.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.topic&lt;/code&gt; to &lt;code&gt;createTopics&lt;/code&gt; string.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;[{&amp;quot;topic&amp;quot;: &amp;quot;Temperature&amp;quot;,&amp;quot;partitions&amp;quot;: 3,&amp;quot;replicationFactor&amp;quot;:1}]&lt;/code&gt;, you can create as many topics as you want at a time.&lt;/li&gt;
&lt;li&gt;Drag the Kafka admin node onto Canvas.&lt;/li&gt;
&lt;li&gt;Connect the inject node’s output to the Kafka admin node’s input.&lt;/li&gt;
&lt;li&gt;Deploy the flow by clicking on the top-right red deploy button.&lt;/li&gt;
&lt;li&gt;After the Deploy, click on the inject button to create a topic.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing set payload in inject node for creating new Kafka topic&quot; alt=&quot;Screenshot showing set payload in inject node for creating new Kafka topic&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-inject-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing Node-RED flow for creating new kafka topic&quot; alt=&quot;&amp;quot;Screenshot showing Node-RED flow for creating new kafka topic&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-creating-topic.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;sending-data-to-kafka-topic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#sending-data-to-kafka-topic&quot;&gt;Sending Data to Kafka topic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this part, we’ll be setting up a producer to send simulated city region temperature data to Kafka. The producer will populate one of the available partitions in our temperature topic.&lt;/p&gt;
&lt;p&gt;We’ve already set up the temperature topic with 3 partitions. We’ll use these partitions to send data from each city region across the city (downtown region, suburban region, and industrial region). The partitioning process keeps the data separated, making it easier and faster to work with and analyze.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a Kafka producer node onto Canvas.&lt;/li&gt;
&lt;li&gt;Selected added Kafka configuration.&lt;/li&gt;
&lt;li&gt;Click on that node and add the topic that we have created, set the key as &lt;code&gt;downtown&lt;/code&gt;, and set the partition number as 0. (The partition index starts from zero)&lt;/li&gt;
&lt;li&gt;Drag an inject node onto Canvas.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;$floor($random() * 100)&lt;/code&gt; as a JSON expression and set the inject node to send the payload automatically after a specific interval of time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing kafka producer configuration&quot; alt=&quot;&amp;quot;Screenshot showing kafka producer configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-kafka-producer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;receiving-data-from-kafka-topic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#receiving-data-from-kafka-topic&quot;&gt;Receiving data from Kafka topic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will be creating consumers who will subscribe to listen to downtown region temperature data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag the Kafka consumer node onto Canvas.&lt;/li&gt;
&lt;li&gt;Selected added Kafka configuration.&lt;/li&gt;
&lt;li&gt;Click on that node, add the topic that we have created, and enter partition &lt;code&gt;0&lt;/code&gt; from which it will read temperature data.&lt;/li&gt;
&lt;li&gt;Add the Change node onto the Canvas and set &lt;code&gt;msg.topic&lt;/code&gt; to &lt;code&gt;msg._kafka.key&lt;/code&gt; and &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;$number(msg.payload)&lt;/code&gt; because the Kafka custom node we are using is converting number data into a string. (consumer returns a Kafka object containing information related topic’s partition from data received, a key which we have set in the producer section to recognize data, and other information)&lt;/li&gt;
&lt;li&gt;Add the ui-chart node on to Canvas and select the created group in which the chart will render.&lt;/li&gt;
&lt;li&gt;Connect the Kafka consumer node’s output to change the node’s input and change the node’s output to the chart node’s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing kafka consumer configuration&quot; alt=&quot;&amp;quot;Screenshot showing kafka consumer configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-kafka-consumer.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Changing payload received from Kafka consumer&quot; alt=&quot;&amp;quot;Changing payload received from Kafka consumer&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Repeat the same steps to create producer and consumer for the rest of the two regions suburban and industrial, ensuring to set partitions 1 and 2 for, as we have already assigned partition 0 to the first producer created.&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#deploying-the-flow&quot;&gt;Deploying the flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our temperature monitoring system is now complete and ready for deployment. To initiate the deployment process, locate the red &#39;Deploy&#39; button positioned in the top right corner and navigate to &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing Node-RED flow of Real-time temperature monitoring system&quot; alt=&quot;&amp;quot;Screenshot showing Node-RED flow of Real-time temperature monitoring system&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-temperature-monitoring-system-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing Dashboard 2.0 view of Real-time temperature monitoring system&quot; alt=&quot;&amp;quot;Screenshot showing Dashboard 2.0 view of Real-time temperature monitoring system&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-with-node-red-temperature-monitoring-system.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we’ve gone over everything you need to know about how to get started with Kafka and Node-RED. additionally, in this article, we’re going to focus on solving a problem where the sensor data across the city need to be centrally stored for efficient monitoring and visualization. By solving this problem step-by-step, you’ll understand how to integrate Kafka into your Node-RED applications.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/flowfuse-gallarus-strategic-partnership-to-accelerate-industry-4-adoption/</id>
        <title>FlowFuse and Gallarus Announce Strategic Partnership to Accelerate Industry 4.0 Adoption</title>
        <summary>Strategic partnership to empower businesses with low-code development for Industry 4.0 Transformation</summary>
        <updated>2024-03-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/flowfuse-gallarus-strategic-partnership-to-accelerate-industry-4-adoption/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse, a leading provider of the low-code end-to-end development platform for industrial applications, and Gallarus Industry Solutions Limited, the leading industry 4.0 integrator in Europe dedicated to digital transformation through the deployment of the Unified Namespace (UNS) digital architecture, today announced an exciting strategic partnership. This collaboration aims to empower businesses with advanced solutions for Industry 4.0 transformation and optimized operational efficiency.&lt;/p&gt;
&lt;p&gt;Powered by Node-RED, FlowFuse enables teams of all sizes to harness low-code capabilities to build robust applications with unparalleled scalability, and security. FlowFuse’s collaborative environment and scalable architecture ensure that teams can build securely and together for continuous development and operational success. Gallarus, with its extensive experience in digital transformation projects and industrial technology integration, will leverage its expertise in high-quality project implementation, support, and maintenance. Together, they offer a comprehensive solution for businesses seeking to digitally transform their operations.&lt;/p&gt;
&lt;p&gt;“We are pleased to announce this strategic alliance with Gallarus,” said Zeger-Jan van de Weg, CEO at FlowFuse. “This partnership signifies a significant step forward in providing businesses with the tools they need to excel in the current digital landscape. By combining our expertise, we are confident in delivering exceptional value to our customers.”
“This partnership with FlowFuse perfectly aligns with our mission to empower businesses with transformative industry 4.0 solutions,” said Patrick Mc Carthy, COO at Gallarus Industry Solutions Limited. “FlowFuse&#39;s low-code development platform, combined with our expertise in UNS architecture and integration, will provide a powerful solution for organizations of all sizes to move away from an Industry 3.0 mentality and embrace Industry 4.0, streamlining operations to unlock new levels of efficiency not seen before.”&lt;/p&gt;
&lt;p&gt;This combined expertise will address the complexities of digital transformation for businesses by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Facilitating data access, transformation, and visualization across any protocol.&lt;/li&gt;
&lt;li&gt;Breakdown data silos enabling organization-wide data availability via the UNS.&lt;/li&gt;
&lt;li&gt;Enable citizen developers to build extremely useful industrial applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more information about FlowFuse and Gallarus Industry Solutions Limited, please visit their respective websites at &lt;a href=&quot;http://flowfuse.com/&quot;&gt;flowfuse.com&lt;/a&gt; and &lt;a href=&quot;http://gis.ie/&quot;&gt;gis.ie.&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/dashboard-getting-started/</id>
        <title>Getting Started with Node-RED Dashboard 2.0</title>
        <summary>New to Node-RED? New to Dashboard 2.0? This guide will help you get started.</summary>
        <updated>2024-03-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/dashboard-getting-started/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;With our latest release of Node-RED Dashboard 2.0, we&#39;ve made some big improvements to the onboarding experience.&lt;/p&gt;
&lt;p&gt;We&#39;re seeing over 2,000 people download Dashboard 2.0 per week, and are seeing a great buzz in the community of brand new Node-RED users, experienced Node-RED users that haven&#39;t explored a UI solution previously and existing users migrating from Dashboard 1.0.&lt;/p&gt;
&lt;p&gt;So, with that in mind, we wanted to offer a new &amp;quot;Getting Started&amp;quot; guide that will help you get up and running with building custom user interfaces and data visualizations in Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;how-to-install-node-red-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#how-to-install-node-red-dashboard-2.0&quot;&gt;How to Install Node-RED Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;step-1%3A-%22manage-palette%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#step-1%3A-%22manage-palette%22&quot;&gt;Step 1: &amp;quot;Manage Palette&amp;quot;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot to show where to find the &amp;quot;Manage Palette&amp;quot; option in Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-manage-palette.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot to show where to find the &quot;Manage Palette&quot; option in Node-RED&lt;/figcaption&gt;
&lt;ol&gt;
&lt;li&gt;Click the Node-RED Settings (top-right)&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Manage Palette&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-2%3A-search-%26-%22install%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#step-2%3A-search-%26-%22install%22&quot;&gt;Step 2: Search &amp;amp; &amp;quot;Install&amp;quot;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot to show where to find the &amp;quot;Install&amp;quot; tab, and how to find @flowfuse/node-red-dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-search-install.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot to show where to find the &quot;Install&quot; tab, and how to find @flowfuse/node-red-dashboard&lt;/figcaption&gt;
&lt;ol&gt;
&lt;li&gt;Switch to the &amp;quot;Install&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Search for &lt;em&gt;&amp;quot;@flowfuse/node-red-dashboard&amp;quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Install&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;adding-your-first-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#adding-your-first-widgets&quot;&gt;Adding your first widgets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the nodes installed, getting started is as easy as choosing a node from the Palette (the left-hand side list of nodes) in Node-RED, and dropping it onto your canvas.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screen recording to show how easy it is to deploy your first Dashboard 2.0 application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-add-widget.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screen recording to show how easy it is to deploy your first Dashboard 2.0 application.&lt;/figcaption&gt;
&lt;p&gt;In this case, we drop in a &lt;code&gt;ui-button&lt;/code&gt;, click &amp;quot;Deploy&amp;quot; and then can see the button running live in our user interface.&lt;/p&gt;
&lt;p&gt;Notice too that Dashboard will automatically setup some underlying configurations for you (visible in the right-side menu):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ui-base&lt;/code&gt;: Each instance of Node-RED that uses Dashboard 2.0 must have a single &lt;code&gt;ui-base&lt;/code&gt; element (we&#39;re hoping to add support for multiple in the future). This element contains all of the global settings for your Dashboard instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ui-page&lt;/code&gt;: A single Dashboard (&lt;code&gt;ui-base&lt;/code&gt;) can consist of multiple pages, and can be navigated to using the left-side sidebar. Each page is then responsible for displaying a collection of &lt;code&gt;ui-group&lt;/code&gt; elements.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ui-group&lt;/code&gt;: Each group contains a collection of widgets, and can be used to organize your Dashboard into logical sections.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ui-theme&lt;/code&gt;: Each &lt;code&gt;ui-page&lt;/code&gt; can be assigned a given theme. Your &amp;quot;Themes&amp;quot; provide control over the aesthetic of your Dashboard like color, padding and margins.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;configuring-your-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#configuring-your-layout&quot;&gt;Configuring your layout&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dashboard 2.0 adds a dedicated sidebar to Node-RED to provide a centralized view of your pages, groups and widgets. From here you can add new pages and groups, modify existing settings, and re-order content to your liking.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot showing the Dashboard 2.0 sidebar in the Node-RED Editor.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot showing the Dashboard 2.0 sidebar in the Node-RED Editor.&lt;/figcaption&gt;
&lt;p&gt;When defining your layout options, we break the choice into two sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Page Layout:&lt;/strong&gt; Controls how the &lt;code&gt;ui-groups&lt;/code&gt;&#39;s are presented on a given page in your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation Sidebar:&lt;/strong&gt; Defines the left-side navigation style, defined at the &lt;code&gt;ui-base&lt;/code&gt; level.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example of a &amp;quot;Grid&amp;quot; page layout, with &amp;quot;Collapsing&amp;quot; sidebar navigation.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-layout.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Example of the &quot;Grid&quot; page layout, with &quot;Collapsing&quot; sidebar navigation.&lt;/figcaption&gt;
&lt;h3 id=&quot;page-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#page-layout&quot;&gt;Page Layout&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Currently, we have three different options for page layout:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Grid:&lt;/strong&gt; (&lt;a href=&quot;https://dashboard.flowfuse.com/layouts/types/grid.html&quot;&gt;docs&lt;/a&gt;) This is the default layout for a page, and uses a 12-column grid system to layout your &lt;code&gt;ui-groups&lt;/code&gt;. Widths of groups and widgets define the number of columns they will render in. So, a &amp;quot;width&amp;quot; of 6&amp;quot; would render to 50% of the screen. Grid layouts are entirely responsive, and will adjust to the size of the screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fixed:&lt;/strong&gt; (&lt;a href=&quot;https://dashboard.flowfuse.com/layouts/types/fixed.html&quot;&gt;docs&lt;/a&gt;) Each component will render at a &lt;em&gt;fixed&lt;/em&gt; width, no matter what the screen size is. The &amp;quot;width&amp;quot; property is converted a fixed pixel value (multiples of 48px by default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notebook:&lt;/strong&gt; (&lt;a href=&quot;https://dashboard.flowfuse.com/layouts/types/notebook.html&quot;&gt;docs&lt;/a&gt;) This layout will stretch to 100% width, up to a maximum width of 1024px, and will centrally align. It&#39;s particularly useful for storytelling (e.g. articles/blogs) or analysis type user interfaces (e.g. Jupyter Notebooks), where you want the user to digest content in a particular order through scrolling.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;navigation-sidebar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#navigation-sidebar&quot;&gt;Navigation Sidebar&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dashboard 2.0 offers various options on the appearance of the navigation sidebar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Collapsing:&lt;/strong&gt; When the sidebar is opened the page content will adjust with the width of the sidebar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fixed:&lt;/strong&gt; The full sidebar will always be visible, and the page content will adjust to the width of the sidebar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collapse to Icons:&lt;/strong&gt; When minimized, users can still navigate between pages by clicking on the icons representing each page in the sidebar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Appear over Content:&lt;/strong&gt; When the sidebar is opened, the page is given an overlay, and the sidebar sits on top.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always Hide:&lt;/strong&gt; The sidebar will never show, and navigation between pages can instead be driven by &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-control.html&quot;&gt;&lt;code&gt;ui-control&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;define-your-layout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#define-your-layout&quot;&gt;Define Your Layout&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our example, we&#39;re going to switch to a &amp;quot;Notebook&amp;quot; layout, with a &amp;quot;Collapse to Icons&amp;quot; sidebar:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Example of the &amp;quot;Notebook&amp;quot; layout and &amp;quot;Collapse to icons&amp;quot; sidebar&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-example.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Example of the &quot;Notebook&quot; layout, with &quot;Collapse to Icons&quot; sidebar navigation.&lt;/figcaption&gt;
&lt;h2 id=&quot;adding-more-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#adding-more-widgets&quot;&gt;Adding More Widgets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, we&#39;re going to build a quick example to demonstrate how we can wire nodes together, and visualize the output from a &lt;code&gt;ui-slider&lt;/code&gt; onto a &lt;code&gt;ui-chart&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;adding-a-group&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#adding-a-group&quot;&gt;Adding a Group&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the Node-RED Editor&#39;s Dashboard 2.0 sidebar, we&#39;re going to then do the following things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Edit &amp;quot;My Group&amp;quot; and rename it to &amp;quot;Controls&amp;quot;&lt;/li&gt;
&lt;li&gt;Create a new &amp;quot;Group&amp;quot; in your existing page called &amp;quot;Data Visualization&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&#39;ll now see the two groups listed under &amp;quot;Page 1&amp;quot;. &amp;quot;Controls&amp;quot; with a single &lt;code&gt;ui-button&lt;/code&gt; and &amp;quot;Data Visualization&amp;quot; with no widgets.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the modified and newly added groups&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-new-group.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot of the modified and newly added groups&lt;/figcaption&gt;
&lt;h3 id=&quot;connecting-new-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#connecting-new-nodes&quot;&gt;Connecting New Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Then, we&#39;re going to add two new widgets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Chart&lt;/li&gt;
&lt;li&gt;UI Slider&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which we can do by dropping them from the left-side Palette and onto our canvas.&lt;/p&gt;
&lt;p&gt;We&#39;ll need to double-click each new node and confirm which &amp;quot;Group&amp;quot; we want to add this node to. In this case, we&#39;ll add the &lt;code&gt;ui-slider&lt;/code&gt; to the &amp;quot;Controls&amp;quot; group, and the &lt;code&gt;ui-chart&lt;/code&gt; to the &amp;quot;Data Visualization&amp;quot; group.&lt;/p&gt;
&lt;p&gt;We&#39;re also going to connect the output from both the &lt;code&gt;ui-slider&lt;/code&gt; and &lt;code&gt;ui-button&lt;/code&gt; to the input of the &lt;code&gt;ui-chart&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Node-RED Editor, showing the ui-slider and ui-button connected to our ui-chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot of the Node-RED Editor, showing the ui-slider and ui-button connected to our ui-chart&lt;/figcaption&gt;
&lt;p&gt;Now, when we view our Dashboard, we can see the &lt;code&gt;ui-slider&lt;/code&gt; output is def straight into our &lt;code&gt;ui-chart&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Screenshot of the Dashboard with all three widgets rendered&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-final.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Screenshot of the Dashboard with all three widgets rendered&lt;/figcaption&gt;
&lt;p&gt;The final step we&#39;re going to make is to modify our &lt;code&gt;ui-button&lt;/code&gt;. We&#39;re going to rename it to &amp;quot;Clear&amp;quot;, and configure it&#39;s &amp;quot;Payload&amp;quot; option to send a JSON payload of &lt;code&gt;[]&lt;/code&gt;, which, when sent to the &lt;code&gt;ui-chart&lt;/code&gt; will clear the chart of all data.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;The ui-button configuration after setting it&#39;s payload and label&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-btn-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;The ui-button configuration after setting it&#39;s payload and label&lt;/figcaption&gt;
&lt;p&gt;With all of this together, we have the following functional Dashboard:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;Short animation showing the final functional dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-getting-started-final.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption&gt;Short animation showing the final functional dashboard.&lt;/figcaption&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst this is just a simple introduction of Node-RED Dashboard 2.0, we do have many other articles and documentation that can help you get started with more advanced features.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/dashboard/&quot;&gt;FlowFuse Dashboard Articles&lt;/a&gt; - Collection of examples and guides written by FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0 Documentation&lt;/a&gt; - Detailed information for each of the nodes available in Dashboard 2.0, as well as useful guides on building custom nodes and widgets of your own.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discourse.nodered.org/tag/dashboard-2&quot;&gt;Node-RED Forums - Dashboard 2.0&lt;/a&gt; -  The Node-RED forums is a great place to ask questions, share your projects and get help from the community.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;Beginner Guide to a Professional Node-RED&lt;/a&gt; - A free guide to an enterprise-ready Node-RED. Learn all about Node-RED history, securing your flows and dashboard data visualization.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;FlowFuse - Book a Demo&lt;/a&gt; - FlowFuse provides a complete platform to scale your production Node-RED applications, increase developer velocity, and enhance security in order to accelerate innovation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;New features and improvements are coming to Node-RED Dashboard 2.0 every week, if you&#39;re interested in what we have lined up, or want to contribute yourself, then you can track the work we have lined up on our GitHub Projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/5&quot;&gt;Dashboard 1.0 Feature Parity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/</id>
        <title>Securing HTTP Traffic for Node-RED with FlowFuse</title>
        <summary>Choosing the right form of authentication for your Node-RED integration is important.</summary>
        <updated>2024-03-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Citizen development empowers employees to create digital solutions. However, it requires guardrails to ensure data security, operational stability, and compliance. These guardrails are what FlowFuse provides to the Node-RED community to level up their deployments. FlowFuse offers many different security measures for authentication and authorization, which all apply to different scenarios.&lt;/p&gt;
&lt;p&gt;In this post we’ll take a look at most of them, specifically for HTTP traffic. We’ll discuss the trade-offs for auditabliltiy, convenience to use as either machine or human, among other factors.&lt;/p&gt;
&lt;h2 id=&quot;http-basic-authentication%3A-a-simple-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/#http-basic-authentication%3A-a-simple-approach&quot;&gt;HTTP Basic Authentication: A Simple Approach&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HTTP Basic Authentication is widely supported and straightforward to implement, making it a popular choice for securing APIs. It requires users to provide a username and password before accessing the Node-RED instance. While this method is easy to use, it&#39;s important to note that the username and password are shared and transmitted in plain text, making it vulnerable to interception if the connection doesn&#39;t leverage SSL/TLS. FlowFuse by default ensures SSL/TLS is deployed.&lt;/p&gt;
&lt;h2 id=&quot;personal-access-tokens%3A-knowing-who-accessed-the-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/#personal-access-tokens%3A-knowing-who-accessed-the-node-red&quot;&gt;Personal access tokens: Knowing who accessed the Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Personal access tokens (PATs) are an essential component of FlowFuse, allowing users to securely access their accounts without sharing their passwords. These tokens are generated by the user and can be used to authenticate to the SaaS product&#39;s API or other services. PATs provide a more secure alternative to traditional username/password authentication, as they can be revoked or regenerated at any time, limiting the potential impact of a compromised token.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-authentication%3A-seamless-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/#flowfuse-authentication%3A-seamless-integration&quot;&gt;FlowFuse Authentication: Seamless Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse authentication offers a seamless and secure way for users to access dashboards and other resources that are typically accessed through a browser. It leverages single sign-on (SSO) and SAML 2.0, reducing the management burden for organizations.&lt;/p&gt;
&lt;p&gt;For users this is convenient as they can access multiple applications and resources using a single set of credentials, eliminating the need to remember and manage multiple passwords.&lt;/p&gt;
&lt;p&gt;For organizations, SSO enhances security by centralizing authentication and authorization, reducing the risk of unauthorized access. By leveraging SSO and SAML 2.0, FlowFuse takes care of user management, freeing up customers from the administrative burden of managing user accounts and passwords. FlowFuse authentication adheres to industry-standard security protocols, ensuring compliance with regulatory requirements.&lt;/p&gt;
&lt;p&gt;This method of authentication is however impractical for API access by other services, to programmatically transfer data between them.&lt;/p&gt;
&lt;h2 id=&quot;bearer-authentication%3A-a-token-based-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/#bearer-authentication%3A-a-token-based-approach&quot;&gt;Bearer Authentication: A Token-Based Approach&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bearer Authentication offers a more secure and flexible alternative to traditional username/password authentication. Users will generate the token through the FlowFuse platform with each instance generating its own token. These tokens can be designed to have limited lifespans, reducing the risk if compromised. In the case the token then becomes compromised only the instance in which the token is generated can become subject to malicious behaviors. In the case that this does occur, simply deleting the token will elevate any unwanted access.&lt;/p&gt;
&lt;p&gt;Compared to FlowFuse Authentication, this method is very well suited for API access and programmatic access to FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;choosing-the-right-authentication-strategy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/#choosing-the-right-authentication-strategy&quot;&gt;Choosing the Right Authentication Strategy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse provides multiple authentication mechanisms to cater to various aspects of security and user experience. When designing your Node-RED applications, consider the specific requirements of your project and the patterns of user interaction to select the most appropriate authentication strategy. By doing so, you can ensure both a high level of security and an optimal user experience for your web development projects with API calls through Node-RED.&lt;/p&gt;
&lt;p&gt;In conclusion, understanding and utilizing these different types of authentication in FlowFuse empowers citizen developers like you to create more secure and efficient applications for diverse use cases.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/</id>
        <title>Scaling Node-RED with FlowFuse: Differences between a FlowFuse Instance and a Device Instance</title>
        <summary>Managing your Node-RED instances is easier with FlowFuse.</summary>
        <updated>2024-03-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse is a Software as a Service (SaaS) platform designed to enhance the experience and capabilities of Node-RED for its users. By focusing on scalability, security, and Dev Ops, FlowFuse aims to remove some of the technical barriers associated with using Node-RED, making it easier for citizen developers to automate tasks, process data, and create applications. In this blog post, we will discuss the differences between a FlowFuse instance and a FlowFuse device instance while highlighting how FlowFuse addresses scalability challenges in Node-RED deployments.&lt;/p&gt;
&lt;h2 id=&quot;scalability-challenges-with-traditional-node-red-deployments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/#scalability-challenges-with-traditional-node-red-deployments&quot;&gt;Scalability Challenges with Traditional Node-RED Deployments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While deploying Node-RED is quite simple, managing multiple instances across different environments can become complex and time-consuming. As the number of devices and use cases grow, users face difficulties in scaling their Node-RED applications efficiently to handle increased load without compromising performance or security. This is where FlowFuse comes into play.&lt;/p&gt;
&lt;h2 id=&quot;the-role-of-flowfuse-as-an-orchestration-tool&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/#the-role-of-flowfuse-as-an-orchestration-tool&quot;&gt;The Role of FlowFuse as an Orchestration Tool&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse functions as an orchestration tool that allows the deployment and management of all your Node-RED instances at scale, addressing scalability challenges head-on. By leveraging its platform, users can quickly deploy and manage multiple Node-RED instances while ensuring optimal performance and security. This enables them to connect with a wide range of devices, from PLCs and sensors to legacy software, without worrying about the complexities of managing their Node-RED deployment.&lt;/p&gt;
&lt;h2 id=&quot;deploying-node-red-next-to-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/#deploying-node-red-next-to-devices&quot;&gt;Deploying Node-RED Next to Devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One common issue in IoT deployments is that device instances of Node-RED often communicate with unsecure devices or networks. To mitigate security risks and ensure data protection, it&#39;s common to deploy Node-RED in close proximity to these devices. The FlowFuse platform uses &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;device agents&lt;/a&gt; that communicate back to the platform via a reverse tunnel over port 443. This setup requires only one firewall rule: allowing outbound connections from the &lt;a href=&quot;https://flowfuse.com/platform/device-agent/&quot;&gt;device agent&lt;/a&gt; running Node-RED to the FlowFuse platform, significantly minimizing security risks while enabling remote monitoring, flow editing, and configuration deployment at scale.&lt;/p&gt;
&lt;h2 id=&quot;deploying-node-red-instances-within-the-flowfuse-platform&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/#deploying-node-red-instances-within-the-flowfuse-platform&quot;&gt;Deploying Node-RED Instances Within the FlowFuse Platform&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not all instances of Node-RED need to be deployed at the edge and can be deployed anywhere. FlowFuse offers this flexibility in cases where users prefer or require deploying their Node-RED instances within the platform itself. This capability allows users to focus on developing and managing their applications without worrying about the underlying infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/scaling-node-red-devices-vs-flowfuse-instance/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse addresses scalability challenges in Node-RED deployments by providing an easy-to-use platform that enables users to manage multiple instances at scale while maintaining security and performance. By understanding the differences between a FlowFuse instance and a device instance, you can make informed decisions about your deployment strategy and leverage the full potential of Node-RED for your applications. Stay tuned for our upcoming blogs where we will dive deeper into the areas of security, dev ops, and backup solutions provided by FlowFuse.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/</id>
        <title>How Kafka is applied in manufacturing</title>
        <summary>An overview of Kafka -- How it&#39;s applied for industrial applications, and how it works</summary>
        <updated>2024-03-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever wondered how manufacturing and automotive industries can effectively manage the vast amount of real-time data generated by sensors and systems throughout the production process? A few years back, these industries faced major obstacles in handling the large volume of real-time data produced by sensors placed across the production line. Even today many industries continue to grapple with similar challenges. Traditional data management systems struggle to process and analyze this data in real-time, leading to inefficiencies in operational activities and decision-making. To address these challenges, various manufacturing and automobile plants have embraced technologies like Apache Kafka.&lt;/p&gt;
&lt;p&gt;Kafka provides a distributed streaming platform that enables the efficient handling of real-time data streams. By leveraging Kafka, we can aggregate, process, and analyze data in real-time seamlessly. This guide provides a high-level overview of Kafka, covering its definition, components, functionality, applications, and limitations.&lt;/p&gt;
&lt;h2 id=&quot;what-is-kafka%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#what-is-kafka%3F&quot;&gt;What is Kafka?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apache Kafka is a platform for distributed data streaming that allows for the publishing, subscribing, storing, and processing of streams of records in real-time. It is intended to handle data streams from multiple sources and to deliver them to multiple consumers. In essence, it can move large quantities of data in real-time from any source to any destination, simultaneously.&lt;/p&gt;
&lt;p&gt;Kafka is also a very good &lt;a href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/&quot;&gt;broker for UNS architecture&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;understanding-kafka&#39;s-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#understanding-kafka&#39;s-architecture&quot;&gt;Understanding Kafka&#39;s Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kafka architecture is designed to provide a scalable and fault-tolerant platform for handling real-time data streams. The architecture consists of several key components, each component serves a specific purpose in the data processing pipeline. In this section, we will take an overview of Kafka&#39;s architecture and its key components.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Architecture of Kafka&quot; alt=&quot;&amp;quot;Architecture of Kafka&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-kafka-in-manufacturing-kafka-architecture.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Topics and Partitions&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Topics: Imagine topics as folders for organizing data – they act as distinct categories. Kafka arranges information into these topics for systematic storage.&lt;/li&gt;
&lt;li&gt;Partitions: Think of partitions as subdivisions within topics. They enable parallel processing across multiple servers, enhancing fault tolerance and throughput.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Producers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Producers: Producers are like architects of data flow. They decide where to send records within a topic. This decision can be balanced using a round-robin or directed by a record key for specific purposes, such as maintaining order.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. Brokers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Definition: Brokers are the backbone servers in a Kafka cluster.&lt;/li&gt;
&lt;li&gt;Tasks: Brokers store data, handle requests from both producers and consumers, and maintain the integrity and persistence of data. They also manage the critical task of tracking offsets, which determine the position of consumers within partitions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Consumers and Consumer Groups:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consumers: These entities read data from brokers. They subscribe to one or more topics and pull data from the specific partitions they are interested in.&lt;/li&gt;
&lt;li&gt;Consumer Groups: Consumers collaborate in groups to scale data processing. Kafka dynamically assigns each consumer in a group a set of partitions from the subscribed topics, ensuring that each partition is processed by only one consumer within the group.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5. Offsets&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Definition: Offsets act as unique identifiers for records within a partition. They denote the position of a consumer in the partition.&lt;/li&gt;
&lt;li&gt;Function: As consumers read records, they increment their offset. This allows them to resume processing from where they left off, which is crucial for handling failures or restarts. Kafka stores offset information in a specialized topic for easy recovery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6. Replication&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mechanism: Kafka ensures data durability by replicating partitions across multiple brokers.&lt;/li&gt;
&lt;li&gt;Replication Factor: This configurable setting determines the number of copies of a partition in the cluster. If one broker fails, another can seamlessly take over, guaranteeing high availability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;features-of-kafka&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#features-of-kafka&quot;&gt;Features of Kafka&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we&#39;ve gained a foundational understanding of Kafka, let&#39;s explore the key features that make it a preferred choice for many organizations. These features highlight why Kafka transcends being just another data processing tool and why it merits consideration for various use cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;High Throughput and Scalability:&lt;/strong&gt; Kafka can handle thousands of messages per second and can scale horizontally and vertically to meet growing data demands without compromising performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault Tolerance and Reliability:&lt;/strong&gt; Built to ensure reliability, Kafka guarantees fault tolerance through replication, safeguarding data against loss in the event of a broker failure. Data redundancy ensures data safety even during hardware failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-Time Processing and Low Latency:&lt;/strong&gt; Kafka&#39;s real-time processing ensures low latency for instant data analysis, which is critical for real-time decision-making.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;applications-of-kafka&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#applications-of-kafka&quot;&gt;Applications of Kafka&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As we explore the capabilities of Kafka, we realize that it goes beyond being just a regular data processing tool. Kafka is a strategic powerhouse that influences decision-making, operational efficiency, and overall effectiveness in various industries. In this section, we will discuss specific, practical applications of Kafka in different industries, demonstrating how its adaptability can solve unique challenges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Manufacturing Operations Optimization:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time Production Monitoring: Kafka is used in manufacturing for continuous monitoring of production lines, equipment status, and inventory levels. This real-time visibility aids in optimizing production efficiency, reducing downtime, and enhancing overall supply chain management.&lt;/li&gt;
&lt;li&gt;Quality Assurance and Yield Management: Companies utilize Kafka to monitor quality control metrics in real-time, enabling proactive measures to maintain product quality standards, minimize defects, and optimize production yield.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Predictive Maintenance:&lt;/strong&gt; Organizations use Kafka to collect and analyze sensor data from machinery and equipment to predict potential failures. This helps them optimize scheduled maintenance tasks to prevent costly downtime and disruptions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Supply Chain Management:&lt;/strong&gt; Kafka provides real-time visibility into supply chain operations. This enables companies to track shipments, monitor inventory levels, and coordinate with suppliers and distributors for efficient supply chain management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Logistics and Transportation:&lt;/strong&gt; Companies use Kafka to track vehicle and shipment locations in real-time, optimizing routes through the processing of streams of GPS data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Telecommunications:&lt;/strong&gt; Telecom operators utilize Kafka to monitor network performance metrics in real-time. This allows swift responses to outages or service degradations, ensuring a seamless communication network.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Financial Services:&lt;/strong&gt; Banks leverage Kafka to process transactions in real-time, enabling immediate fraud detection by analyzing patterns in transaction data as they occur. This enhances overall security and compliance in financial operations.&lt;/p&gt;
&lt;h2 id=&quot;challenges-and-considerations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#challenges-and-considerations&quot;&gt;Challenges and Considerations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As beneficial as Kafka is in various industries, it also presents certain limitations and challenges that must be considered before deciding to use Kafka for your applications.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Performance: Kafka both receives and transmits data. When the flow of data is compressed or decompressed, the performance is affected. For example, if the data is decompressed it will eventually drain the node memory. As a result, it affects both throughput and performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complexity: As we all know Kafka is an excellent platform for streamlining messages. However, in the case of migration projects that transform data, Apache Kafka gets more complex. Hence, to interact with both data producers and consumers you need to create data pipelines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tool Support: There is always a concern for startup companies to use Kafka over other options.  Especially, if it remains in the long run. This is because a full set of management and monitoring tools are absent in Kafka.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Message Tweaking: Kafka uses system calls before delivering a message. Therefore, the messages are sensitive to modifications. Tweaking messages reduces the performance of Kafka to a greater extent. The performance is not impacted only under the condition of not changing the message.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data Storage: Apache Kafka is not a recommended option for storing large sets of data. If the data is stored for a long period, the redundant copies of it are also stored. When this happens, the app must be ready to compromise its performance. For this reason, only use Kafka if there is a need to store data for a short period.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additionally, if you are interested in learning more about Kafka and its practical implementation, refer to our guide on Using &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka with Node-RED&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-in-manufacturing/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide provides a high-level overview of Apache Kafka, including its definition, architecture, features, and applications in various industries and the challenges or limitations of using Kafka. Kafka&#39;s versatility in real-time data processing, decision-making, and operational efficiency is highlighted, with applications ranging from manufacturing to finance. The overview aims to provide a clear understanding of Kafka&#39;s role in handling data challenges and fostering innovation across sectors.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/flowfuse-self-hosted-starter-resource-limits/</id>
        <title>FlowFuse Open Source Starter Tier Resource Limits</title>
        <summary>The first 5 Node-RED runtimes are part of the starter package going forward</summary>
        <updated>2024-03-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/flowfuse-self-hosted-starter-resource-limits/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Today, with the latest FlowFuse release, an important change was made that
updates the resource limits for our open-source, self-managed FlowFuse server
tier. This change does not affect FlowFuse Cloud users in any way.&lt;/p&gt;
&lt;h2 id=&quot;new-starter-tier-resource-limits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/flowfuse-self-hosted-starter-resource-limits/#new-starter-tier-resource-limits&quot;&gt;New Starter Tier Resource Limits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The new limit for the number of Node-RED runtimes on the Starter tier is 5.
These 5 instances can be distributed across a maximum of 5 teams. This revised
structure allows for the development of your initial FlowFuse and Node-RED
solutions, providing a clear understanding of how FlowFuse can enhance your
organization&#39;s workflows. Upgrading to a Team or Enterprise tier license unlocks
the full potential of FlowFuse and grants access to our dedicated support team.&lt;/p&gt;
&lt;h2 id=&quot;why-the-change%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/flowfuse-self-hosted-starter-resource-limits/#why-the-change%3F&quot;&gt;Why the Change?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here at FlowFuse, we&#39;re committed to providing a great experience for all our
users, including those utilizing our free, open-source Starter tier.  We
initially designed this tier to offer a platform for small organizations and
larger teams to explore FlowFuse&#39;s capabilities without needing our direct
involvement. However, we&#39;ve observed instances where the Starter tier&#39;s free
limits were being used to run very large deployments and even entire sites.&lt;/p&gt;
&lt;p&gt;While support is a key benefit we offer to paying customers, we believe everyone
deserves a positive FlowFuse experience. As such, we&#39;re adjusting the resource
limits to better align with the Starter tier&#39;s intended purpose and allow the
company to continue to invest in the Starter tier.&lt;/p&gt;
&lt;h2 id=&quot;transitioning-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/flowfuse-self-hosted-starter-resource-limits/#transitioning-users&quot;&gt;Transitioning Users&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re currently impacted by these resource limit changes, we want to ensure
a smooth transition. We&#39;re offering a complimentary 1-year Enterprise license to
affected users. To claim your license, simply email support@flowfuse.com with
the IP address your server has used to send telemetry data (if available) and a
screenshot of your admin panel so we can match the currently usage with the new
license.&lt;/p&gt;
&lt;p&gt;We appreciate your understanding and continued support. If you have any
questions regarding this update, please don&#39;t hesitate to reach out to our team
at support@flowfuse.com.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/low-code-is-better/</id>
        <title>Why Low-Code is Better</title>
        <summary>Stop coding in High-Code when it can be done in Low-Code</summary>
        <updated>2024-03-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/low-code-is-better/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;There are two common reasons why new languages come about.  They provide a feature missing in the existing programming languages, or it is a tool that is easier to learn and use.  The latter often functions like a swiss army knife with each iteration including more and more tools.  The journey of low-code is like a swiss army knife, the perfect tool for the Citizen Developer.&lt;/p&gt;
&lt;h2 id=&quot;a-typical-coding-evolution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/low-code-is-better/#a-typical-coding-evolution&quot;&gt;A Typical Coding Evolution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every decade seems to introduce something that simplifies coding. For me, in college, it was Python. A classmate was excited about this new programming language that was all about simplicity and readability, especially with its indentation-based syntax. It seemed too simple at first. Yet, over time, Python became a staple in my programming toolbox.&lt;/p&gt;
&lt;p&gt;During this time in our education, our coursework was filled with languages like C++, which felt distant from the future of programming we imagined. We joked about &amp;quot;outdated&amp;quot; languages, not yet realizing the breadth of what programming could encompass.&lt;/p&gt;
&lt;p&gt;After finishing college in 2010, I started working during the tail end of the housing crisis in the U.S. My first role was as a Controls System Integrator at Logical System Inc., where I was introduced to programming PLCs with Ladder Logic. Despite my initial reservations—viewing it as barely a programming language—this experience was my first step towards appreciating the diversity and utility of programming languages beyond the conventional.&lt;/p&gt;
&lt;p&gt;Later on in my career, I worked as a Corporate Automation and Controls Engineer where I worked on and enforced standards for partner System Integrators and OEMs.  One of these important standards was making sure applications written in the control process were written in Ladder Logic within the PLCs.  There were exceptions, of course, but the rule was to apply a visually appealing coding language, Ladder Logic, over a text-like language often called Structured Text.&lt;/p&gt;
&lt;h2 id=&quot;programming-languages-as-specialized-tools&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/low-code-is-better/#programming-languages-as-specialized-tools&quot;&gt;Programming Languages as Specialized Tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Programming languages are typically optimized for certain tasks. For instance, Matlab and R excel in complex numerical computations thanks to their extensive libraries designed specifically for mathematical operations. While Python might not replace Matlab or R for their core functionalities, it can broaden the applicability of numerical analyses into various other contexts. In another example, VB.net is the go-to for standalone applications in Windows environments. However, for applications that need to run across different operating systems (excluding web applications), Java might be a better choice due to its platform independence. Each programming language has its niche, along with inherent complexities and constraints.&lt;/p&gt;
&lt;p&gt;There are situations, however, where the specific strengths of a programming language become less critical. In cases where the application is straightforward, the choice of language might simply come down to personal preference or familiarity. But an important consideration arises when thinking about the future of the project: &amp;quot;Will someone else need to edit or view this code later?&amp;quot; If the answer is yes, and especially if the project aims to involve citizen developers, opting for a low-code solution becomes highly advantageous. Low-code platforms are designed with accessibility in mind, making them ideal for projects that benefit from collaboration and ease of maintenance.&lt;/p&gt;
&lt;h2 id=&quot;the-purpose-of-citizen-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/low-code-is-better/#the-purpose-of-citizen-development&quot;&gt;The Purpose of Citizen Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The idea behind Citizen Development is simple, make programming accessible to more people. This is what low-code platforms aim to do. They lower the entry barrier, making programming more inclusive. Insisting on complex, traditional programming languages when there are simpler, equally powerful alternatives seems counterproductive. We should be looking towards making programming more accessible to everyone.&lt;/p&gt;
&lt;p&gt;If we want to drive meaningful change within our organizations, embracing tools that broaden participation is key. The aim of adopting new standards and tools is to simplify, not complicate. It&#39;s about finding better, more accessible ways to work that can accommodate a wider range of skill sets.&lt;/p&gt;
&lt;h2 id=&quot;simplification&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/low-code-is-better/#simplification&quot;&gt;Simplification&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This discussion isn&#39;t about the mechanics of coding, it&#39;s about opening up the field to more diverse contributions. Low-code platforms represent a step towards a more inclusive, collaborative future in technology. By lowering barriers to entry, we&#39;re not just simplifying coding, we&#39;re inviting a broader community to engage, innovate, and drive progress. I look forward to seeing how we can all contribute to this evolving landscape.&lt;/p&gt;
&lt;h2 id=&quot;how-flowfuse-helps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/low-code-is-better/#how-flowfuse-helps&quot;&gt;How FlowFuse Helps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our goal here at FlowFuse is to keep expanding on the Swiss army knife, Node-RED. We strive to elevate Node-RED for professionals by providing the tools needed to deploy Node-RED in a safe and secure way.  For example by default, the editor for Node-RED is protected using your FlowFuse user credentials. You can also use SSO to further protect your user accounts and give access to Node-RED to your team members. All traffic to FlowFuse and your Node-RED instances is protected by HTTPS. FlowFuse has set up the domain name and manages the certificates so you can spend time on your flows rather than configuring security.&lt;/p&gt;
&lt;p&gt;We believe that Low-Code is the future and strive to make Citizen Development a reality. To learn more &lt;a href=&quot;https://flowfuse.com/free-consultation/&quot;&gt;schedule a call with one of our experts. &lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/</id>
        <title>Looking towards Node-RED 4.0 and beyond</title>
        <summary>A look at what is coming in Node-RED 4.0</summary>
        <updated>2024-03-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;With Node-RED 4.0 coming soon, I wanted to take a look at what users can expect to see with the new release,
as well as some of the new features we&#39;re working on.&lt;/p&gt;
&lt;p&gt;The Node-RED project &lt;a href=&quot;https://nodered.org/about/releases/&quot;&gt;schedules its releases&lt;/a&gt; around a yearly major release that coincides with when a Node.js version
reaches its end-of-support. This lets us drop support for that node.js version and update the default version of node used
in the docker containers we publish. We treat this as a major change because  it might require actions on the end-users part to update any additional modules they have installed.&lt;/p&gt;
&lt;p&gt;With Node-RED 4.0, we will be dropping support for anything earlier than Node 18 - with Node 20 the currently recommended version to use. That will give users almost 2 full years before needing to consider another Node.js upgrade.&lt;/p&gt;
&lt;p&gt;Now, talking about Node.js versions is not that exciting. What is more exciting is to look at what new features are coming to Node-RED.&lt;/p&gt;
&lt;p&gt;There are a few things already merged and ready to be released in the first beta release, and more landing each week.&lt;/p&gt;
&lt;h3 id=&quot;more-auto-complete&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#more-auto-complete&quot;&gt;More auto-complete&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED already has simple auto-complete on &lt;code&gt;msg&lt;/code&gt; fields in the editor. We&#39;ve now extended that to also work with &lt;code&gt;flow&lt;/code&gt;/&lt;code&gt;global&lt;/code&gt; context inputs as well as the &lt;code&gt;env&lt;/code&gt; type for accessing environment variables.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Node-RED editor autocompleting properties&quot; alt=&quot;Node-RED editor autocompleting properties&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr4-auto-complete.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This makes it so much easier to work with these types of properties - being sure you&#39;re using something that exists rather than having to switch between different views in the editor to get the names right.&lt;/p&gt;
&lt;p&gt;In the case of env vars, it also shows you where the value was set - useful when you have nested groups and subflows which might be overriding a particular value.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;msg&lt;/code&gt; auto-complete is still based on a built-in list of common message properties used by the core nodes. There is interest in enabling this to pull completions from &#39;live&#39; messages seen by the node in question - but that&#39;s not currently in the plan for 4.0.&lt;/p&gt;
&lt;h3 id=&quot;timestamp-formatting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#timestamp-formatting&quot;&gt;Timestamp formatting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Inject node has provided the ability to inject a timestamp since the very early days of Node-RED. The value it actually sets is the number of milliseconds since epoch (aka January 1st, 1970). If you&#39;re used to working with JavaScript, then this is a perfectly normal way to pass times around. However, it isn&#39;t always what is needed and flows end up using a Function node to reformat it in some way.&lt;/p&gt;
&lt;p&gt;With 4.0 we&#39;ve added options to pick what format the timestamp is generated in at the start. Now, formatting times and dates can be a big can of worms of options. So, for this initial release, we&#39;ve kept it simple by offering three options:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Format options for Node-RED timestamp&quot; alt=&quot;&amp;quot;Format options for Node-RED timestamp&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr4-timestamp-formatting.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;milliseconds since epoch&lt;/em&gt; - the existing option, just more explicitly labelled for what it is&lt;/li&gt;
&lt;li&gt;&lt;em&gt;YYYY-MM-DDTHH:mm:ss.sssZ&lt;/em&gt; - also known as ISO 8601&lt;/li&gt;
&lt;li&gt;&lt;em&gt;JavaScript Date Object&lt;/em&gt; - the standard Date object&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is scope to allow custom format strings to be set in the node - but we&#39;ll see what the feedback is on these new options first.&lt;/p&gt;
&lt;h3 id=&quot;a-better-csv-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#a-better-csv-node&quot;&gt;A better CSV node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The CSV node has had a big overhaul to make it more standards compliant. It turns out CSV has a whole bunch of tricky edge cases that most users don&#39;t hit - but if you did hit them you would be stuck.&lt;/p&gt;
&lt;p&gt;The new node follows the &lt;a href=&quot;https://www.ietf.org/rfc/rfc4180.txt&quot;&gt;RFC4180&lt;/a&gt; standard and is also faster - wins all around.&lt;/p&gt;
&lt;p&gt;For those flows that rely on some of the non-standard edge case behaviour of the existing node, we&#39;ve kept a legacy mode in place to keep those flows working.&lt;/p&gt;
&lt;h3 id=&quot;customising-config-nodes-in-subflows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#customising-config-nodes-in-subflows&quot;&gt;Customising config nodes in Subflows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This one needs a bit of explaining. Subflows are a way Node-RED lets you create a flow and add multiple reusable instances of it within your flows. For example, a subflow may connect to an MQTT broker and do some standard processing on the messages it received before sending them on. The Subflow can then expose a set of properties that can be customised for each instance. In our example, that could be the topic the MQTT node subscribes to.&lt;/p&gt;
&lt;p&gt;However, in that example, the MQTT node&#39;s broker configuration would be locked to the same broker config node in every instance - and that&#39;s something we&#39;re solving in Node-RED 4.0.&lt;/p&gt;
&lt;p&gt;We&#39;re making it possible to expose the choice of a configuration node in the Subflow properties - so each instance can be customised even further.&lt;/p&gt;
&lt;p&gt;Another common use for this will be with Node-RED Dashboard - which uses config nodes to set the location of a widget. With Node-RED today, you cannot really use dashboard nodes inside subflows as you end up with multiple copies of the widgets all packed into the same group. With this update, you&#39;ll be able to configure the subflow instance with exactly what dashboard group to place its contents into.&lt;/p&gt;
&lt;h3 id=&quot;updated-jsonata&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#updated-jsonata&quot;&gt;Updated JSONata&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The JSONata library is used to provide the &lt;code&gt;expression&lt;/code&gt; types in Node-RED - a really powerful way of working with JSON objects. With this release we&#39;ve updated to the new major release of JSONata that comes with a bunch of performance improvements.&lt;/p&gt;
&lt;h3 id=&quot;and-many-more-minor-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#and-many-more-minor-changes&quot;&gt;And many more minor changes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&#39;ll hold off listing them all out here, but there are plenty of other smaller changes scattered through the editor and the core nodes. Be sure to check the beta release notes when it arrives to see what else has been done.&lt;/p&gt;
&lt;h2 id=&quot;looking-further-ahead&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#looking-further-ahead&quot;&gt;Looking further ahead&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst all of these are great incremental improvements to Node-RED, there are some bigger items we&#39;re looking at that will really improve the overall Node-RED experience.&lt;/p&gt;
&lt;p&gt;I wrote recently about improving how users can &lt;a href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#testing&quot;&gt;test their flows&lt;/a&gt;. This remains something I think we really help make Node-RED stand apart from other low-code solutions. It won&#39;t be in the imminent 4.0 release, but it is definitely still on the roadmap for a future release.&lt;/p&gt;
&lt;h3 id=&quot;concurrent-editing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#concurrent-editing&quot;&gt;Concurrent editing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another area we want to improve is the collaboration experience within Node-RED. Working on flows as a team is a key feature of FlowFuse, and we want to make it even easier to do.&lt;/p&gt;
&lt;p&gt;One of the common complaints is how Node-RED currently handles multiple users editing flows at the same time. Whilst it&#39;s better than it used to be, it still makes for a very jarring experience when you have to keep merging other users&#39; changes into your own.&lt;/p&gt;
&lt;p&gt;Our goal is to make collaboration as simple and natural as possible.&lt;/p&gt;
&lt;p&gt;There are a wide range of approaches we could take here. For example, a small improvement would be to merge other users&#39; changes in the background without interrupting what you&#39;re doing. But I think we do better than that.&lt;/p&gt;
&lt;p&gt;What if the editing experience was more like Google Docs - knowing that other users have the editor open, and being able to see their changes in real time. This would make for a truely collaborative editing experience.&lt;/p&gt;
&lt;p&gt;There are some difficult problems to solve before we can get there, but I think this will be one of the more transformational changes to Node-RED we&#39;ve had for some time.&lt;/p&gt;
&lt;h2 id=&quot;beta-releases&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/looking-towards-node-red-4/#beta-releases&quot;&gt;Beta releases&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://nodered.org/about/releases/&quot;&gt;release plan&lt;/a&gt; has Node-RED 4.0 coming around the end of April. As mentioned, we&#39;ll be doing a series of beta releases between now and then to start getting early feedback from the community.&lt;/p&gt;
&lt;p&gt;Keep an eye on the &lt;a href=&quot;https://discourse.nodered.org/c/news/9&quot;&gt;community forum&lt;/a&gt; for release announcements as they come.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/03/installing-operating-node-red-behind-firewall/</id>
        <title>Installing and operating Node-RED behind a firewall</title>
        <summary>FlowFuse was built to empower Node-RED to run everywhere, even behind a firewall</summary>
        <updated>2024-03-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/03/installing-operating-node-red-behind-firewall/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Practitioners using Node-RED often find themselves in a situation where a firewall
is deployed in their organization. This network configuration is a fact of life and is generally not controlled by the same people using Node-RED. Given security reigns supreme in Industrial IoT (IIoT), and a firewall offers a lot of benefits, we anticipate it will be deployed more often in the future, and as such it’s good to understand how you can get the most out of Node-RED when deployed behind a firewall.&lt;/p&gt;
&lt;h2 id=&quot;node-red-installation-with-a-firewall&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/installing-operating-node-red-behind-firewall/#node-red-installation-with-a-firewall&quot;&gt;Node-RED installation with a firewall&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generally, the standard install procedure for Node-RED requires a connection to the NPM servers that host the package. Due to NPM’s unaudited nature, IT is unlikely to agree to a permanent exception to the firewall to allow access to it. However, there are a couple of actions one can take to install Node-RED anyway.&lt;/p&gt;
&lt;p&gt;First, ask for a temporary exception. Node-RED is installed in a few minutes, so if there’s a set time schedule an exception can be made there’s a regular method available again through collaboration with the network administrator. The second option is leveraging vendor specific package managers. As these are vetted repositories, it’s not uncommon that these gates in the firewall have been created and opened to you. Some vendors supply repositories for major package managers like &lt;code&gt;apt-get&lt;/code&gt; on Debian/Ubuntu-based systems, or there’s a marketplace approach to install Node-RED like for example the &lt;a href=&quot;https://developer.community.boschrexroth.com/t5/Store-and-How-to/FlowFuse-Node-RED/ba-p/82135&quot;&gt;Rexroth CtrlX with Node-RED in it&lt;/a&gt;. Lastly, you could consider downloading the NPM package beforehand and transferring it to your machine within the network. NPM allows the installation of local packages, which in turn allows you to create applications with Node-RED. This is generally a shadow IT action, and not recommended unless it’s approved.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-and-your-firewall&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/installing-operating-node-red-behind-firewall/#flowfuse-and-your-firewall&quot;&gt;FlowFuse and your firewall&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As FlowFuse can be installed in a VPN behind a firewall, there’s no requirement to open up a ‘gate’ in your firewall to FlowFuse servers. The safe perimeter provided remains to the outside world. The security aspect remains, though as a Node-RED developer, there are still everyday tasks you’ll need access to the outside world.&lt;/p&gt;
&lt;p&gt;Consider installing third party nodes to connect your Node-RED instance to virtually any protocol or digital service. There are over 5000 of these nodes available, and as an organization it’s challenging to keep on top of. Your firewall provides one layer of security so that the data you’re accessing remains safe. FlowFuse provides a second layer of protection; we’ve introduced a &lt;a href=&quot;https://flowfuse.com/certified-nodes/&quot;&gt;“Certified Nodes” catalog&lt;/a&gt;. These nodes have gone through automated and manual inspection to prevent malicious code from making it onto your production systems.&lt;/p&gt;
&lt;p&gt;Installing these packages would typically still require you to obtain files from NPM. With FlowFuse however, a cache can be built with only vetted nodes – All other nodes remain unavailable.&lt;/p&gt;
&lt;p&gt;Once Node-RED is installed and the initial development has been completed, FlowFuse aims to reduce the maintenance burden on both IT and OT teams too. In the same package cache aforementioned, Node-RED versions can be added. Updating Node-RED to the latest version becomes a job of just a few clicks. Updating your Node-RED instances, even behind a firewall, is imperative, as virtually all breaches are the result of daisy-chaining multiple security vulnerabilities into a high to critical event.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/03/installing-operating-node-red-behind-firewall/#wrap-up&quot;&gt;Wrap up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse founding engineers have decades of experience running Node-RED wherever it is valuable. Our product is the culmination of that, and we’re excited to help you become successful in your digitalization efforts – even when a firewall is in play.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/history-of-nodered/</id>
        <title>History of Node-RED</title>
        <summary>How it all started as told by Node-RED creator Nick O&#39;Leary</summary>
        <updated>2024-02-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/history-of-nodered/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;In January 2013, I could have never foreseen that my fun little proof-of-concept project would become Node-RED, an open source low-code environment with millions of deployments in IoT and automation.&lt;/p&gt;
&lt;p&gt;Long before IoT became the ubiquitous term it is today, I was working in IBM’s Emerging Technology Group playing around with capturing data from devices and doing interesting things with it. The team focused on very fast-paced, short, proof-of-concept projects and was afforded time to learn new skills, innovate and work on side projects.&lt;/p&gt;
&lt;p&gt;My background working with the MQTT protocol space before it was known outside of IBM led me to a side project: I wanted some way to visualize mapping messages on an MQTT infrastructure to see how they come in on one topic and get sent out on another.&lt;/p&gt;
&lt;p&gt;Using it as an excuse to also start playing the relatively new Node.js runtime, I spent a day or two putting together a little demo of an application that would connect to an MQTT broker and visualize the topic mappings in a web browser.&lt;/p&gt;
&lt;p&gt;Showing it to my colleague, Dave Conway-Jones, I mentioned it wouldn&#39;t take much to make it more interactive; to let you draw the mappings and apply them. He sent me on my way to do just that and, 24 hours later, I had a simple browser-based application that could define and apply mappings between MQTT topics.&lt;/p&gt;
&lt;p&gt;It very quickly became useful.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/history-nr-screenshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p class=&quot;italic&quot; style=&quot;font-size: 0.9em; margin-top: -1rem;&quot;&gt;An early screenshot of Node-RED&lt;/p&gt;
&lt;p&gt;The projects Dave and I were working on became rich sources of requirements; each project needing to access data from some other source such as a device plugged into a serial port, or being able to modify the data with a bit of JavaScript code.&lt;/p&gt;
&lt;p&gt;I spent a few days redesigning the code to make it easier to write in new nodes, unlocking the ability to quickly add in the function node, change node, and switch node, which became the basic building blocks of the tool.&lt;/p&gt;
&lt;p&gt;The utility of the application was clear, and more colleagues started making use of it - all grounded in real client projects. But it was still a tool largely known only to our team.&lt;/p&gt;
&lt;h3 id=&quot;going-open-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/history-of-nodered/#going-open-source&quot;&gt;Going Open Source&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we considered how best to move the project forward, we essentially had two choices; keep it to ourselves and see if we could get an IBM product group to back turning it into a fully-fledged product, or to go the open source route. In my mind, the OSS route was the natural fit and that is what we ultimately chose to do, getting it published in late 2013.&lt;/p&gt;
&lt;p&gt;I demoed Node-RED in late 2013 at a London IoT meetup and word spread among my peers in that community. A week later, I was at an open source hardware conference and attended a workshop on home automation. I was surprised to see Node-RED on everyone’s screens! The facilitator had seen Node-RED and reworked his workshop so that people didn’t have to worry about writing lines of code and were able to do useful things much more quickly.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/history-ibm-lab.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p class=&quot;italic&quot; style=&quot;font-size: 0.9em; margin-top: -1rem;&quot;&gt;The IBM Emerging Technology Demo Lab - many of the demos were built on Node-RED&lt;/p&gt;
&lt;h3 id=&quot;building-an-audience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/history-of-nodered/#building-an-audience&quot;&gt;Building an audience&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A key step forward was when IBM was preparing to launch its new IBM Cloud service. In the months before the launch, they were looking for innovative ideas that could help expand the offering. We put forward a proposal to use this tool we&#39;d created as a way to visualise the mapping of web services within the cloud.&lt;/p&gt;
&lt;p&gt;This generated some great interest from a wider audience within the company, and whilst that concept didn&#39;t ultimately come to anything, we had gotten our project noticed.&lt;/p&gt;
&lt;p&gt;Over time, we started seeing Node-RED being picked up by more than just the OSS community. Companies started using it with their own hardware devices and online services.&lt;/p&gt;
&lt;p&gt;By this time, IBM Cloud had launched, and from our previous conversations with them, we got Node-RED included as one of the &#39;starter applications&#39; in the catalogue that gave users a one-click option for getting Node-RED running in the cloud.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/history-cloud-catalog.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p class=&quot;italic&quot; style=&quot;font-size: 0.9em; margin-top: -1rem;&quot;&gt;Node-RED in the original IBM Cloud catalog&lt;/p&gt;
&lt;h3 id=&quot;moving-to-a-foundation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/history-of-nodered/#moving-to-a-foundation&quot;&gt;Moving to a Foundation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As we saw the project grow, discussions were had around the longer-term future of the project. Some companies voiced a concern about it being a single-vendor open source project. This also came at a time when IBM was actively working with the Node.js project to help relaunch the Node Foundation (which has since become the OpenJS Foundation). This culminated in Node-RED joining the foundation as one of its founding projects, alongside other well-established projects such as Node.js itself, jQuery and many others.&lt;/p&gt;
&lt;p&gt;Having an independent governance structure around the project gave companies more confidence to get involved, knowing they had an equal voice in its development. Hitachi became big supporters of the project and had a team dedicated to working on it.&lt;/p&gt;
&lt;p&gt;For software developers, time spent writing boilerplate code is not time adding value to the application they’re building. With low-code, Node-RED abstracts all that boilerplate so they can focus on the business problem.&lt;/p&gt;
&lt;p&gt;Device manufacturers paid attention when Node-RED was installed on the Raspberry Pi image, with its low-code accessibility attracting a broad range of people from systems engineers building automations to IoT hobbyists.&lt;/p&gt;
&lt;p&gt;Now with millions of deployments, Node-RED continues to collect, transform, and integrate data through visualized dashboards. And, as this open source community grows it remains rooted in the two pillars of its low-code user experience, and its extensibility.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/</id>
        <title>Citizen Development: Unleashing Domain Experts</title>
        <summary>Why you should encourage domain experts to build applications</summary>
        <updated>2024-02-26T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Citizen development has taken the spotlight recently, but the concept itself isn&#39;t entirely new. Remember the era of &amp;quot;hackers&amp;quot;? They weren&#39;t malicious actors, but individuals who tinkered with technology, pushing boundaries and creating solutions. Today, these same problem-solving personas have evolved into &amp;quot;&lt;a href=&quot;https://www.gartner.com/en/information-technology/glossary/citizen-developer&quot;&gt;citizen developers&lt;/a&gt;&amp;quot; – business users empowered to build applications without relying solely on professional coders.&lt;/p&gt;
&lt;h2 id=&quot;why-now%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/#why-now%3F&quot;&gt;Why Now?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the drive for user-friendliness has always been present in programming languages, several factors have converged to push citizen development to the forefront:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Democratization of Technology: Cloud computing and advancements in low-code/no-code platforms have lowered the barrier to entry, making development tools accessible to individuals with minimal technical expertise.&lt;/li&gt;
&lt;li&gt;Business Agility: The need for rapid innovation necessitates solutions that bypass lengthy IT backlogs. Citizen developers can bridge the gap, creating applications and internal tools quickly and efficiently.&lt;/li&gt;
&lt;li&gt;Domain Expertise: Business users possess deep insights into specific processes and challenges. By giving them the tools to build solutions, organizations can tap into a new knowledge source by putting domain experts into the driver&#39;s seat.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;beyond-spreadsheets%3A-platforms-of-empowerment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/#beyond-spreadsheets%3A-platforms-of-empowerment&quot;&gt;Beyond Spreadsheets: Platforms of Empowerment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reports and Dashboards are often created by a BI teams that have to take information from specialists to create custom visualizations that may or may not come out to be exactly what they asked for. Queue old faiful, spreadsheets, where a domain expert can create their own reports that suit their needs.  Spreadsheets are powerful for analysis, but they often lack the real-time secure connectivity needed for enterprise applications. Transform the knowledge created in a spreadsheet into a personalized real-time visualization. To do that, you must first select a citizen development platform and those platforms should offer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visual Interfaces: Drag-and-drop functionality and pre-built components eliminate the need for complex coding, allowing users to focus on logic and functionality.&lt;/li&gt;
&lt;li&gt;Integration Capabilities: Seamless connection with existing data sources and systems ensures that citizen-built applications integrate seamlessly into the overall workflow. Plus, the ability to create custom integrations.&lt;/li&gt;
&lt;li&gt;Governance and Security: IT governance establishes guardrails while empowering users, ensuring data security and application stability through features like Role Based Access Control and SSO integration.&lt;/li&gt;
&lt;li&gt;Collaboration Tools: Built-in collaboration features enable teams to share ideas, iterate on solutions, and ensure knowledge transfer.&lt;/li&gt;
&lt;li&gt;Reseliency: Backup management.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;citizen-developers%3A-not-rube-goldberg-machines%2C-but-value-creators&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/#citizen-developers%3A-not-rube-goldberg-machines%2C-but-value-creators&quot;&gt;Citizen Developers: Not Rube Goldberg Machines, But Value Creators&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The key to successful citizen development lies in empowerment, not abdication. By providing the right tools, training, and governance, organizations can avoid creating complex, fragile solutions. Instead, citizen developers become powerful problem-solvers, building value-driven applications that address specific needs and contribute to overall business goals.&lt;/p&gt;
&lt;h2 id=&quot;lean-in&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/why-citizen-development-platforms/#lean-in&quot;&gt;Lean In&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Remember, citizen development isn&#39;t about replacing professional developers. It&#39;s about creating a collaborative environment where everyone can contribute their unique skills and perspectives. By removing the coding barrier, we unleash a wider pool of innovators, accelerating progress and driving organizational success.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/</id>
        <title>Storing Data: Getting Started with Node-RED</title>
        <summary>Node-RED is one of the easiest ways to program ever created but everyone needs a little help</summary>
        <updated>2024-02-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;It&#39;s quite straightforward to pass plenty of useful data with each message (msg) in your flows. Not only can you store information in msg.payload, but you can also place information in any other named object, for instance, msg.store.&lt;/p&gt;
&lt;p&gt;In this article, we will explore some of the better solutions for storing and retrieving transactional information in your flows.&lt;/p&gt;
&lt;h4 id=&quot;storing-data-outside-of-msg.payload&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/#storing-data-outside-of-msg.payload&quot;&gt;Storing data outside of msg.payload&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this example, we have data in msg.payload as well as in msg.later.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Storing data outside of msg.payload&quot; alt=&quot;Storing data outside of msg.payload&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/data-outside-msg-payload.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you want your debug to display the full content of the message, change the output to &#39;complete message object&#39; as shown above.&lt;/p&gt;
&lt;p&gt;You can import the flow using this code.&lt;/p&gt;
&lt;div id=&quot;nr-flow-176&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow176 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;aaa1e17e5f158004&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject the message&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;later&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;A string I want to be able to use later in my flow&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;Hello World&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bce1bf09736125b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bce1bf09736125b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow176.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-176&#39;) })&lt;/script&gt;
&lt;p&gt;Storing data outside of msg.payload can be very useful when you need access to that data later in your flow. You may notice that many nodes overwrite the content of msg.payload, so putting your data elsewhere is essential otherwise, it will be overwritten and lost.&lt;/p&gt;
&lt;h4 id=&quot;tidying-your-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/#tidying-your-messages&quot;&gt;Tidying your messages&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You may also want to remove data you don&#39;t need from your messages to optimize the speed of your flows.&lt;/p&gt;
&lt;p&gt;It&#39;s easy enough to remove data you don&#39;t need, wherever it sits within your messages using the Change Node. In this example, we are going to delete the content of msg.other while leaving the rest of the message to be passed to the next Node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Deleting data from msg.other&quot; alt=&quot;Deleting data from msg.other&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/delete-other.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The Change Node is configured as follows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Change Node configuration&quot; alt=&quot;Change Node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/delete.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can import the flow using this code.&lt;/p&gt;
&lt;div id=&quot;nr-flow-177&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow177 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;1ac51e71153f7c1f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject the message&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;other&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;We don&#39;t need this string anymore&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;Hello World&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:530,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;5d3a978ad9eab443&#92;&quot;,&#92;&quot;cd7609101328caa2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5d3a978ad9eab443&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:60,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cd7609101328caa2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;other&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:730,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;be2f7f68dee570be&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;be2f7f68dee570be&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 3&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow177.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-177&#39;) })&lt;/script&gt;
&lt;h4 id=&quot;storing-data-outside-of-msg.payload-so-you-can-access-it-later-in-your-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/#storing-data-outside-of-msg.payload-so-you-can-access-it-later-in-your-flows&quot;&gt;Storing data outside of msg.payload so you can access it later in your flows&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Storing data outside of msg.payload allows you to access it later in your flows. In this example, we inject geographical coordinates and use an API to get the sunset time for each location. We can then output the result as a sentence.&lt;/p&gt;
&lt;p&gt;As the HTTP Node, which we are using to interact with the weather API, overwrites msg.payload with the response, we will store the submitted city name and coordinates in msg.store for later use.&lt;/p&gt;
&lt;p&gt;You can see the flow working below.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example flow which gets the sunset time for a given location&quot; alt=&quot;Example flow which gets the sunset time for a given location&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sunset-example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can import the flow using this code.&lt;/p&gt;
&lt;div id=&quot;nr-flow-178&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow178 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;809cc8f4678767b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;London&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.city&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;London&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lat&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;51.5072&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lng&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;0.1276&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b5a6a2ef7a64f1a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b86d2d558eebbd7e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Washington DC&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.city&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Washington DC&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lat&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;38.9072&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.lng&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;77.0369&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:140,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b5a6a2ef7a64f1a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aaecc81a2de233d6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 4&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b5a6a2ef7a64f1a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;store&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;273ee743f8d1a5f1&#92;&quot;,&#92;&quot;af43cea5866e11f5&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;273ee743f8d1a5f1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;create the URL&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;url&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;https://api.sunrisesunset.io/json?lat={{store.lat}}&amp;amp;lng={{store.lng}}&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;52e8913233f379eb&#92;&quot;,&#92;&quot;1d94053c790791ee&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af43cea5866e11f5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 5&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:160,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;52e8913233f379eb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;obj&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aaecc81a2de233d6&#92;&quot;,&#92;&quot;a245b322ade3a7e9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1d94053c790791ee&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 6&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a245b322ade3a7e9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Create the sentence&#92;&quot;,&#92;&quot;field&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;fieldType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;handlebars&#92;&quot;,&#92;&quot;syntax&#92;&quot;:&#92;&quot;mustache&#92;&quot;,&#92;&quot;template&#92;&quot;:&#92;&quot;The sun will set at  in .&#92;&quot;,&#92;&quot;output&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3e4b2d3644845f91&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3e4b2d3644845f91&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 7&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1040,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow178.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-178&#39;) })&lt;/script&gt;
&lt;p&gt;Using this technique, we can build the content of message.store (or any other name you&#39;d like to use) and then output the content at the end of a flow, even if you use msg.payload to interact with APIs and other custom nodes.&lt;/p&gt;
&lt;h4 id=&quot;why-not-store-the-values-in-context%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/#why-not-store-the-values-in-context%3F&quot;&gt;Why not store the values in context?&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Where possible, it&#39;s more robust to store all the information related to a particular message within the message rather than saving it to context and retrieving it later. Using context risks a &lt;a href=&quot;https://en.wikipedia.org/wiki/Race_condition#:~:text=A%20race%20condition%20or%20race,to%20unexpected%20or%20inconsistent%20results&quot;&gt;race condition&lt;/a&gt; within your flow that could result in data corruption.&lt;/p&gt;
&lt;p&gt;In this example, we simulate how a race condition can make context a bad choice for transactional data storage. The flow passes in the name and age of two people then moves the age to context. The flow then adds a random delay for each message so that, in some cases, the messages do not reach the debug in the order they were created. After the delay, the age is pulled back from context and added to each msg.payload.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example of how a race condition can make context a bad place to cache data&quot; alt=&quot;Example of how a race condition can make context a bad place to cache data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/race-condition.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If there is a race condition in play, we should intermittently see Rob and John&#39;s stored ages being assigned to the wrong person. We can see in the image above that Rob is showing the incorrect age.&lt;/p&gt;
&lt;p&gt;You can import the flow using this code.&lt;/p&gt;
&lt;div id=&quot;nr-flow-179&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow179 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;7ac4e7165d99f041&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Rob&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.name&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Rob&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.age&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;46&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1e0575bd662f9277&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e9c0baba4f50b0b2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;John&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.name&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;John&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;payload.age&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;29&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:880,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1e0575bd662f9277&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d5f688682206d316&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;age&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.age&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d56225e59bde93cf&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d56225e59bde93cf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;delete&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.age&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d5a119b311bf8377&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e3ec11b4e038e564&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 8&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d5a119b311bf8377&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b329d7f2685d0ed6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b329d7f2685d0ed6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload.age&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;age&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:900,&#92;&quot;y&#92;&quot;:940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e3ec11b4e038e564&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e0575bd662f9277&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;delay&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;67746003c844dbc4&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pauseType&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;timeoutUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;rate&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;nbRateUnits&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;rateUnits&#92;&quot;:&#92;&quot;second&#92;&quot;,&#92;&quot;randomFirst&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;randomLast&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;randomUnits&#92;&quot;:&#92;&quot;seconds&#92;&quot;,&#92;&quot;drop&#92;&quot;:false,&#92;&quot;allowrate&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:700,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d5f688682206d316&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow179.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-179&#39;) })&lt;/script&gt;
&lt;h4 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/taking-it-further-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Storing transactional data in msg rather than context in Node-RED offers advantages in modularity, scalability, simplicity, and also helps prevent race conditions. By using msg, data transfer between nodes becomes more seamless, allowing for independent node reuse across flows without additional configuration. This approach ensures scalability by avoiding the imposition of large datasets on the global context. Moreover, storing data outside of msg.payload within the msg object enhances flexibility. It separates metadata and other relevant information from the main payload, promoting a cleaner and more organized structure. This practice not only aligns with Node-RED&#39;s visual programming paradigm but also improves code readability. Steering clear of context for transactional data, while also organizing it within the msg object, provides a comprehensive and reliable solution within the Node-RED framework.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://sunrisesunset.io/&quot;&gt;SunriseSunset&lt;/a&gt; for creating the useful API we&#39;ve used in this article.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/</id>
        <title>Node-RED in a Unified Namespace Architecture</title>
        <summary>How does Node-RED elevate a Unified Namespace Architecture?</summary>
        <updated>2024-02-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;As we embark on the journey toward a more interconnected industrial environment, the emergence of a Unified Namespace (UNS) as the fundamental framework for facilitating communication among various systems and devices has become a focal point of discussion. I&#39;ve often been queried about the role of Node-RED in a UNS architecture. To illuminate this, let&#39;s delve into an exemplary UNS architecture, underlining the classic use cases for Node-RED within this framework.&lt;/p&gt;
&lt;p&gt;In this Article: &lt;a href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/&quot;&gt;Node-RED: The perfect adapter and middleware for your UNS&lt;/a&gt;, where classic use cases for Node-RED are delineated. Building upon that foundation, this discussion aims to present a tangible architectural example, showcasing the practical implementation of these use cases.&lt;/p&gt;
&lt;h2 id=&quot;simplifying-complexity%3A-the-two-layered-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/#simplifying-complexity%3A-the-two-layered-approach&quot;&gt;Simplifying Complexity: The Two-Layered Approach&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For ease of understanding, consider the architecture split into two principal layers: the Shopfloor layer and the Service layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Shopfloor Layer&lt;/strong&gt;
This is where the physical assets dwell, requiring connectivity through a network layer, which in our example, is the UNS. It acts as the foundation for data flow from the operational technology (OT) on the shop floor to the information technology (IT) in the Service layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Service Layer&lt;/strong&gt;
Here resides the applications and software that analyze data, transforming raw metrics into actionable insights. It&#39;s where the data becomes meaningful through analytics, dashboards, and decision-support tools.&lt;/p&gt;
&lt;h2 id=&quot;the-roles-in-uns-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/#the-roles-in-uns-architecture&quot;&gt;The Roles in UNS Architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Within this bifurcated architecture, we have two general categories of actors: Indirect Consumer/Producers and Direct Consumer/Producers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Indirect Consumer/Producers&lt;/strong&gt;:
These actors cannot natively communicate with our UNS broker. The communication barrier could be due to protocol differences, such as not using MQTT, or payload structures incompatible with your UNS&#39;s schema. This is a common challenge in manufacturing, especially in &amp;quot;brownfield&amp;quot; scenarios where legacy machines and equipment from various eras must be integrated.&lt;/p&gt;
&lt;p&gt;In such cases, Node-RED shines as a middleware for protocol conversion and data contextualization. Take, for example, the topic hierarchy in UNS based on location for context. A raw sensor reading might lack necessary details like measurement units or message versions. Node-RED steps in to enrich this data, ensuring compatibility with the UNS. In our &lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/&quot;&gt;concrete architecture example&lt;/a&gt;, we have an indirect PLC producer. With Node-RED, we can convert and contextualize the data from this PLC for the UNS, ensuring smooth communication and effective integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Direct Consumer/Producers&lt;/strong&gt;:
Contrastingly, direct actors can interact with the UNS out of the box. Modern industrial equipment usually falls into this category, equipped to speak the language of the UNS directly. However, the challenge remains not just in protocol communication but also in data contextualization. Merely speaking the same language is not enough; the data must also carry the correct context to be fully understood and utilized.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Example Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/unified-namespace-architecture.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;harnessing-node-red-for-actionable-insights&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-unified-namespace-architecture/#harnessing-node-red-for-actionable-insights&quot;&gt;Harnessing Node-RED for Actionable Insights&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED&#39;s prowess extends beyond middleware capabilities; it can also derive actionable insights. Our example architecture includes Dashboards for both the Human Machine Interface on the Shopfloor and an OEE Dashboard in the Service Layer. These dashboards engage with the UNS, calculating KPIs directly within Node-RED. For manufacturing applications, our &lt;a href=&quot;https://flowfuse.com/blueprints/&quot;&gt;Blueprint Library&lt;/a&gt; serves as a robust starting point, offering one-click deployment to your Node-RED managed instance.
Node-RED emerges not just as a translator between machines and UNS but as an interpreter and analyst, generating real-time insights that drive decision-making and operational efficiency. The role of Node-RED in UNS architecture, therefore, is not ancillary; it is central to realizing the vision of a connected, intelligent industrial ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Andon Live Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ANDON-Screenshot-D4DBvWieJZ-650.avif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/</id>
        <title>Connect Node-RED to KepserverEX OPC server.</title>
        <summary>Step by step guide to connect to PTC&#39;s Kepware OPC server.</summary>
        <updated>2024-02-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;KepserverEX, often referred to as Kepware, is an OPC server that has been the important tool many manufacturing companies have used on their digital transformation journey.  It plays an important role for many to extract data from PLCs, Programmable Logic Controllers, without having to directly interact with them.&lt;/p&gt;
&lt;h2 id=&quot;ptc&#39;s-kepserverex&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#ptc&#39;s-kepserverex&quot;&gt;PTC&#39;s KepserverEX&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PTC&#39;s &lt;a href=&quot;https://www.ptc.com/en/products/kepware/kepserverex-ppc&quot;&gt;KEPServerEX&lt;/a&gt; is a versatile connectivity platform designed to securely manage, monitor, and control diverse automation devices and software applications. Central to its functionality is the OPC standard, which enables universal communication across industrial hardware and software, facilitating data exchange. This makes KEPServerEX particularly valuable in a variety of use cases, such as real-time data monitoring, machine-to-machine (M2M) communication, and industrial Internet of Things (IIoT) applications. It serves as a critical bridge in the automation and controls engineering space, offering a robust solution for integrating disparate systems, thereby enhancing operational efficiency and enabling data-driven decision-making. Integrating KEPServerEX with Node-RED extends this functionality, by allowing bidirectional communication for sending, storing, and or manipulating data.&lt;/p&gt;
&lt;h3 id=&quot;scope&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#scope&quot;&gt;Scope&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The goal of this blog is for a quick start guide on the configuration for collecting data from a KepserverEX OPC server.  We are going to be leveraging the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;node-red-contrib-opcua&lt;/a&gt; node.  We will assume that you already have &lt;a href=&quot;https://www.ptc.com/en/products/kepware/kepserverex-ppc&quot;&gt;KepserverEX&lt;/a&gt; install and ready for the integration. We will be using Basic256Sha256 security in this guide with anonymous authentication.  Assumptions of the installation include allowing Default configuration of the installation of KepserverEX 6.15 and allowing dynamic tag addressing.&lt;/p&gt;
&lt;h3 id=&quot;configure-connection-from-node-red-to-kepserver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#configure-connection-from-node-red-to-kepserver&quot;&gt;Configure Connection from Node-RED to Kepserver&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;step-1%3A-kepserverex&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#step-1%3A-kepserverex&quot;&gt;Step 1: KepserverEX&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first thing we need to do is check our &lt;strong&gt;OPC UA Configuration Manager&lt;/strong&gt; for the security requirements for our environment.  In the tray at the bottom, click on the KepserverEX symbol and select &lt;strong&gt;OPC UA Configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware tray&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kepserverex-tray.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If your Node-RED instance lives on the same server that your KepserverEX is on, pick accordingly or click add if you need to define by ip address. This is for setting different credential requirements for localhost vs remote host access.  Also note, that if you have multiple network adapters, make sure to select the adapter that is in use.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware endpoint definition&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kep-endpoint-definition.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We are testing locally on the server, so we will use the one selected for loopback addressing.  We will be leaving the OPC server port as default and select &lt;strong&gt;Basic256Sha256&lt;/strong&gt; with &lt;strong&gt;Sign and Encrypt&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;OK&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;step-2%3A-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#step-2%3A-node-red&quot;&gt;Step 2:  Node-RED&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Next, navigate to your Node-RED instance and install the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;node-red-contrib-opcua&lt;/a&gt; node if you haven&#39;t already done so.&lt;/p&gt;
&lt;p&gt;Import the flow below into your Node-RED environment.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;225px&quot; src=&quot;https://flows.nodered.org/flow/04a84fe5b0db7cda9e74ba811e7b0ca5/share?height=250&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Next, let&#39;s configure the &lt;strong&gt;OPC UA Client&lt;/strong&gt;.  Click the &lt;strong&gt;pencil&lt;/strong&gt; to add a new OPCUA-Endpoint.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red encrypted opc ua node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-endpoint-node-red-encrypted.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For the endpoint, &lt;strong&gt;copy&lt;/strong&gt; the endpoint definition from the KepserverEX OPC UA Configuration Manager.  In our example, it is &lt;code&gt;opc.tcp://127.0.0.1:49320&lt;/code&gt;, and paste it into the Endpoint.  For SecurityPolicy select &lt;strong&gt;Basic256Sha256&lt;/strong&gt;. For SecurityMode, select &lt;strong&gt;Sign&amp;amp;Encrypt&lt;/strong&gt;.  Lastly, we will be selecting &lt;strong&gt;Anonymous&lt;/strong&gt;.  Click &lt;strong&gt;Update&lt;/strong&gt;, then &lt;strong&gt;Deploy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Trigger the flow by &lt;strong&gt;clicking&lt;/strong&gt; on the inject node.  The server may not connect at this time, and it is expected.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red invalid endpoint&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-opc-ua-invalid-endpoint.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;step-3%3A-kepserverex&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#step-3%3A-kepserverex&quot;&gt;Step 3: KepserverEX&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Moving back over to KepserverEX,  Click on the tray again in the bottom of the screen and select &lt;strong&gt;Configuration&lt;/strong&gt;, then select &lt;strong&gt;Edit&lt;/strong&gt; from the file menu, then &lt;strong&gt;Properties&lt;/strong&gt;.  Next, Select &lt;strong&gt;OPC UA&lt;/strong&gt; and ensure that &lt;strong&gt;Allow Anonymous login&lt;/strong&gt; is set to &lt;strong&gt;Yes&lt;/strong&gt;.  Click &lt;strong&gt;OK&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red anonymous login&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-kepware-anonymous-login.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Select the tray at the bottom of the screen again, and select &lt;strong&gt;OPC UA Configuration&lt;/strong&gt;. Select the &lt;strong&gt;Trusted Clients&lt;/strong&gt; tab.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red trusted client before&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kepserverex-trusted-client-before.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now select the &lt;strong&gt;NodeOPCUA-Client&lt;/strong&gt; and then &lt;strong&gt;click&lt;/strong&gt; Trust.  &lt;em&gt;&lt;strong&gt;If you don&#39;t have the client option, trigger the inject node again from the Node-RED flow and check the logs&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red trusted client after&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kepserverex-trusted-client-after.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;step-4%3A-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#step-4%3A-node-red&quot;&gt;Step 4: Node-RED&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Lastly,  Navigate back to Node-RED and &lt;strong&gt;trigger&lt;/strong&gt; the inject node.  This node will now browse the project from the KepserverEX and display all of the existing tags.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red browsed tags&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kepware-opc-browsed-tags-node-red.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;read-tags&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#read-tags&quot;&gt;Read Tags&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We will be leveraging the default Simulated Examples for reading tags from KepserverEX.  Let&#39;s move on to the next set of flows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red read tags&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-kepware-read-tag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Edit the OPCUa-Item node and note the item.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ns=2;s=Simulation Examples.Functions.Ramp1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s break down the syntax,  ns stands for namespace that will coincide with the project.  In this case, it is namespace 2.  Once the namespace has been selected, we are use &lt;strong&gt;Dynamic Addressing&lt;/strong&gt; to select the tag through the variable &lt;strong&gt;s&lt;/strong&gt;, which stands for string type of NodeId. &lt;strong&gt;Click&lt;/strong&gt; Done.  Now let&#39;s &lt;strong&gt;trigger&lt;/strong&gt; the Read inject node and view the debug output.&lt;/p&gt;
&lt;p&gt;The debug node is set to show a complete msg object.  Note the payload as the value of the variable.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red read tags output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-debug-output-opc.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;write-tag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#write-tag&quot;&gt;Write Tag&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Writing a tag is a similar process.  The only difference is that a variable is set in the &lt;strong&gt;OPCUa-Item&lt;/strong&gt; node and the &lt;strong&gt;OPCUa-Client&lt;/strong&gt; action is set to Write.&lt;/p&gt;
&lt;p&gt;In this example, we created a new variable in KepserverEX under &lt;strong&gt;Simulation Examples &amp;gt; Functions&lt;/strong&gt; called myInt of Date Type Long.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red write tags&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-kepware-write-tag.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;View the OPCUa-Item node and note the item.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ns=2;s=Simulation Examples.Functions.myInt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Click&lt;/strong&gt; Done and &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Open up the &lt;strong&gt;Quick Client&lt;/strong&gt; within KepserverEX and navigate to the address of &lt;strong&gt;Simulation Examples.Functions&lt;/strong&gt; and look for myInt.  It should by default, be 0.  &lt;strong&gt;Trigger&lt;/strong&gt; the inject node within Node-RED to see the Value change within the Quick Client.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red write tags output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-debug-output-write-opc.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;kepware node-red quick client&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/kepware-quick-client.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/connect-node-red-to-kepware-opc/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This guide was designed to help you easily connect your Node-RED instance to KepserverEX with security.  For more examples of how to do more advanced configuration, please watch the past &lt;a href=&quot;https://flowfuse.com/webinars/2023/getting-started-opcua-node-red/&quot;&gt;webinar&lt;/a&gt; going over these &lt;a href=&quot;https://github.com/mikakaraila/node-red-contrib-opcua/tree/master/examples&quot;&gt;examples&lt;/a&gt; in detail.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/software-development-in-node-red/</id>
        <title>Bringing Software Development practices to Node-RED</title>
        <summary>Applying lessons from traditional development to the low-code space.</summary>
        <updated>2024-02-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/software-development-in-node-red/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;I&#39;m always thinking about how we can continue to improve the Node-RED experience. One area I like to explore is to make sure we learn the right lessons from the Software Development world.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;m going to look at some of the common practices in modern Software Development and show how they translate to the Node-RED world.&lt;/p&gt;
&lt;h3 id=&quot;linting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#linting&quot;&gt;Linting&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Linting is a way of examining some code and automatically spotting things that need attention. This can range from stylistic errors (&amp;quot;Use tabs, not spaces&amp;quot;) to real bugs that will prevent the code from working as intended.&lt;/p&gt;
&lt;p&gt;This is all about spotting problems &lt;em&gt;before&lt;/em&gt; the code runs. It also helps ensure consistency when you have multiple people contributing to the code.&lt;/p&gt;
&lt;p&gt;Having code that is consistently formatted and free of syntactic mistakes makes it much easier to maintain.&lt;/p&gt;
&lt;p&gt;Applying this concept to Node-RED, we have the &lt;a href=&quot;https://github.com/node-red/nrlint&quot;&gt;&lt;code&gt;nrlint&lt;/code&gt; tool&lt;/a&gt;. This is a linting tool that can run either on the command-line or within the editor directly to spot potential problems with the flows.&lt;/p&gt;
&lt;p&gt;On the stylistic side, for example, it can highlight nodes that aren&#39;t properly aligned to the grid. Whilst this doesn&#39;t have any bearing on the runtime operation of the flow, it encourages keeping the flows tidy and orderly.&lt;/p&gt;
&lt;p&gt;It can help identify potential infinite loops in flows, and highlight Debug nodes without a name set.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-linter.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;debugging&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#debugging&quot;&gt;Debugging&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whether you are writing lines of code or not, eventually you will need to figure out why your application isn&#39;t doing what you think it should.&lt;/p&gt;
&lt;p&gt;In Software Engineering there are two typical approaches. One is to add debug statements through the code to print out bits of information as the program runs. Then, depending on what output you got, you&#39;d move the debug statements around, add some more, print out different bits of information - all until you&#39;d nailed down the problem. This is the Debug node approach in Node-RED; adding nodes at different points of your flow to capture some piece of information and then iterating as you go.&lt;/p&gt;
&lt;p&gt;This is probably how most Node-RED users go about it today. The downside is you end up leaving the Debug nodes in place, capturing information long after it is needed.&lt;/p&gt;
&lt;p&gt;The alternative approach is Step-by-Step debugging. This is why you are able to pause the program and then step it forward one statement at a time - examining the state at each point. But what&#39;s the equivalent for low-code? Pretty much exactly that when you have the &lt;a href=&quot;https://flows.nodered.org/node/node-red-debugger&quot;&gt;Node-RED Debugger plugin&lt;/a&gt; installed.&lt;/p&gt;
&lt;p&gt;This allows you to set &#39;breakpoints&#39; on any node input or output that are triggered when a message arrives at that point of the flow. The Debugger will then pause the whole runtime and shows you all of the queued up messages in the flow.&lt;/p&gt;
&lt;p&gt;You can then examine those messages and tell the Debugger to &#39;release&#39; them one at a time - seeing how the flow progresses.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-debugger.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;testing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#testing&quot;&gt;Testing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Testing code is a critical part of developing software. You want to make sure it does what you want. But it&#39;s more than just manually testing it once and then letting it go; you want to have tests you can run regularly, whenever you make changes, to ensure you don&#39;t break something that was working previously.&lt;/p&gt;
&lt;p&gt;In the Software Development world, there are all sorts of testing methodologies and techniques; unit testing individual components, system testing larger sections, stubbing out components to simulate different conditions, integrating test suites into the whole development process.&lt;/p&gt;
&lt;p&gt;They each have their own place in the process of software development. The question is, how does this apply to Node-RED?&lt;/p&gt;
&lt;p&gt;Most Node-RED users today will of course be testing their flows whilst developing them - iterating until the flow does what is needed. It&#39;s far less common to have a set of repeatable tests including the flows.&lt;/p&gt;
&lt;p&gt;That is certainly achievable with Node-RED today, albeit with some limitations. For example, a typical test will be to verify that, given a set of particular inputs, the outputs look correct. This can be done using Inject nodes to quickly trigger messages with different values, and use Debug nodes to examine the results.&lt;/p&gt;
&lt;p&gt;That isn&#39;t ideal as you end up littering your flows with these extra Inject nodes, and it still requires manually verifying the results. It also doesn&#39;t work well if your flows need to interact with external systems - such as saving values to a database. You don&#39;t want to pollute your system with test data.&lt;/p&gt;
&lt;p&gt;So what would be the ideal workflow? This is something the project has spent some time exploring in the past, and the start of a design was put together.&lt;/p&gt;
&lt;p&gt;The concept would be to introduce a Testing sidebar to the editor. Within that, you can define a set of test cases. Then for each test case, you can customise the behaviours of individual nodes. For example, a test case may disable an MQTT node at the start of a flow, and tell the runtime to inject a message in its place. For each subsequent node in the flow, the test case would then be able to either to bypass it (to avoid interacting with external systems), or to add checks on what the node outputs. Each test case would then define some criteria for what it means to pass the test.&lt;/p&gt;
&lt;p&gt;As with the Debugger plugin, the Test Runner would be disabled by default - so the &#39;production&#39; flows aren&#39;t modified in anyway. When the Test Runner is enabled, it would then take care of running each test in return and reporting back the results.&lt;/p&gt;
&lt;p&gt;The main challenge is providing a user experience that makes it easy to create these tests in a way that is consistent with the low-code nature of Node-RED.&lt;/p&gt;
&lt;p&gt;Whilst this is very much a future roadmap item for Node-RED, it is one I hope we can start moving forward soon. Having a good, repeatable, testing strategy in Node-RED will make it stand-out from many of the other low-code tools and platforms available today.&lt;/p&gt;
&lt;h3 id=&quot;low-code-vs-lines-of-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#low-code-vs-lines-of-code&quot;&gt;Low-Code vs Lines-of-Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The low-code nature of Node-RED means it is easily accessible to a wide range of users. You don&#39;t need to be a seasoned software engineer to get started.&lt;/p&gt;
&lt;p&gt;If you have a task to solve, and understand it well enough to break it into the right set of steps, translating that into a Node-RED flow can be much easier than having to write all of the corresponding code from scratch.&lt;/p&gt;
&lt;p&gt;Just because you aren&#39;t writing code in Node-RED, it doesn&#39;t mean you shouldn&#39;t be able to benefit from ways of working that are proven to improve the end result - whilst keeping true to the low-code nature of the project.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/software-development-in-node-red/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Both &lt;code&gt;nrlint&lt;/code&gt; and Node-RED Debugger are already pre-installed in all &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; hosted instances. You can start using them today via the sidebar menu.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-sidebar.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/</id>
        <title>Node-RED: The perfect adapter and middleware for your UNS</title>
        <summary>How Node-RED Enhances Connectivity and Efficiency in Unified Namespace Environments.</summary>
        <updated>2024-02-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/"/>
        <author><name>ZJ van de Weg</name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Digitalization is at the inflection point where it’s been adopted enough that the additional investments provided better and better ROIs for organizations. The next bump in ROI will be achieved through the UNS. A torrent of information is more useful when structured and adapted for new use-cases. Either a &lt;a href=&quot;https://flowfuse.com/blueprints/manufacturing/performance-overview/&quot;&gt;performance dashboard&lt;/a&gt;, Artificial Intelligence, or station metrics – each is built faster when the data is readily available and well structured? As a company started around Node-RED, we’ve not spoken a lot where FlowFuse fits into the picture, which is what this post is about.&lt;/p&gt;
&lt;h2 id=&quot;adapting-legacy-machines-to-the-uns&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#adapting-legacy-machines-to-the-uns&quot;&gt;Adapting legacy machines to the UNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The digitalization effort in traditional industries like manufacturing, agriculture, and beyond, has additional challenges due to the high capex assets that need to join in the effort. As these assets will not be replaced, the only way is to adapt them. Adaptation will require tooling that can interact with sensor data regardless of the protocol, data format, and data structures.&lt;/p&gt;
&lt;p&gt;Node-RED bridges the gap between analog and digital data acquisition by seamlessly integrating with a vast array of protocols including serial bus support, Modbus, MQTT, and OPC-UA. Its format agnostic nature allows it to handle diverse data formats, from parsing binary data, to JSON, Protobuf (Sparkplug B), making it a versatile tool for extracting and manipulating data from various sources. With its widespread adoption, Node-RED ensures compatibility with almost every protocol, enabling users to connect and process data from a wide range of devices and applications.&lt;/p&gt;
&lt;h2 id=&quot;contextualisation-of-the-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#contextualisation-of-the-data&quot;&gt;Contextualisation of the data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When data is captured and parsed, it needs to be contextualized. For example; in a UNS the topic hierarchy on which to publish and subscribe to is based on location – that is; context. Furthermore, a raw sensor reading might miss details like the unit of measurement, what message version is required, or doesn’t supply the information in a proper type. All these minor niggles are actual blocking issues for adopting all sensors to the UNS. In some cases makes and models of the sensor might influence the tolerances of readings, it’s a good idea in those cases to include that information in the message.&lt;/p&gt;
&lt;h2 id=&quot;filtering-and-preprocessing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#filtering-and-preprocessing&quot;&gt;Filtering and preprocessing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not all messages are created equal, which was discussed in &lt;a href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/&quot;&gt;an earlier post&lt;/a&gt;. In two of the three examples provided in that post, Node-RED can preprocess or filter information before sending it to the UNS. In the case of big files or binary data, Node-RED can store it in S3 or a network attached storage layer, or even store it locally through a REST interface. The distribution of the event that created the binary data is still published through the UNS though.&lt;/p&gt;
&lt;p&gt;Filtering of data is also a great use-case for Node-RED, generally just a &lt;code&gt;change&lt;/code&gt; node and the data is ready to be published. The flexibility to do virtually anything with captured data is what makes Node-RED such a strong partner for your UNS.&lt;/p&gt;
&lt;h2 id=&quot;continuous-improvement&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#continuous-improvement&quot;&gt;Continuous improvement&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While it would be ideal if data schemas were stable, changes are frequent and unpredictable. It’s a non-obvious requirement for your UNS edge to be adaptable. Message structures can change, to add or remove data from them. Though also the format, from JSON to Sparkplug B, or maybe to XML. Not to say that standardization of messages will continuously require updates to leverage the UNS for higher business value.&lt;/p&gt;
&lt;p&gt;A swiss-army knife as both data sender and receiver is not just a nice-to-have, it’s a requirement.&lt;/p&gt;
&lt;h2 id=&quot;scalable-operations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#scalable-operations&quot;&gt;Scalable operations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While there are other tools available that can adapt to a few protocols, or parse a handful of data formats, there’s no alternative for Node-REDs breadth and depth of integration level. This is why many organizations have already adopted Node-RED for their edge cases, which their current standard solution doesn’t handle.&lt;/p&gt;
&lt;p&gt;There’s no situation where a vendor provided, off-the-shelf solution handles protocols and formats across vendors, modern and legacy OT, that also satisfies the IT requirements unless the extensibility is handled through an Open-Source community, with compliance and security controls from a professional entity surrounding the open source project.&lt;/p&gt;
&lt;h3 id=&quot;how-flowfuse-enhances-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/node-red-perfect-adapter-middleware-uns/#how-flowfuse-enhances-node-red&quot;&gt;How FlowFuse Enhances Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While Node-RED is powerful for implementing UNS, its management and deployment can be complex. FlowFuse simplifies this process with a unified platform that offers one-click deployment, secure management, and scalability for Node-RED applications. It enhances collaboration through centralized management of all Node-RED instances, ensuring streamlined operations and increased efficiency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and explore how FlowFuse can transform your Node-RED experience.&lt;/strong&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/02/professional-services-for-node-red/</id>
        <title>Should You Invest in Professional Services for Your Node-RED Development?</title>
        <summary>Professional Services for Node-RED, When and Why?</summary>
        <updated>2024-02-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/02/professional-services-for-node-red/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Professional services come in many different forms. Anything from setup and configuration, flow development, to node development. In this article, we will cover a few examples of how you can leverage professional services for your Node-RED applications.&lt;/p&gt;
&lt;h2 id=&quot;should-you-invest-in-professional-services-for-your-node-red-development%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#should-you-invest-in-professional-services-for-your-node-red-development%3F&quot;&gt;Should You Invest in Professional Services for Your Node-RED Development?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is multifaceted, and Professional Services (PS) can apply to many use cases.  We will break it down into three categories that will help identify whether PS (Professional Services) is right for you. Those categories will be setup, flow development, and node development. Each takes a different skill set and has different levels of complexity.&lt;/p&gt;
&lt;p&gt;Before we jump into things, we need to understand the value proposition of Node-RED. Why Node-RED? Node-RED is a tool that makes Citizen Development a reality. It should be treated that way throughout the development journey regardless of Professional Services or not. Following standard procedures that minimize complexity, for example: reducing the use of function nodes when other nodes would be more ideal. Don’t overcomplicate things that don’t need to be or better said by this quote.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Easy things should be easy, and hard things should be possible.
-Larry Wall&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#setup&quot;&gt;Setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is often recommended to use PS for the setup and installation of products,
and Node-RED and FlowFuse aren&#39;t different. This becomes especially true if you
desire to professionalize your Node-RED instance. The reason for this is that PS
teams focus on minimizing the risk of application failure, security compromise,
and data/ip loss. This is an area of PS that can easily be overlooked, mainly
there aren&#39;t any negative consequences in the short term. The work these teams focus on prevents catastrophic issues in the future. With Node-RED and FlowFuse, these teams will focus on installing FlowFuse based on system requirements and prerequisites, migrating existing Node-RED instances, securing your environment, and integrating with your existing ecosystem of applications.&lt;/p&gt;
&lt;h3 id=&quot;flow-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#flow-development&quot;&gt;Flow development&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Oftentimes, many think of Flow development when they think of PS for Node-RED. There will be a process flow that needs to be accomplished, but it is leveraging standard nodes built within the Node-RED platform. Occasionally, there will be a need to install a custom node from the pallet manager, but the complexities in the development are adhering to a process and or visualization.  There may be complex data translation, but for the most part, access to the command line of the Node-RED instance is unnecessary. Professional services may be used in situations like this where knowledge of specific systems that Node-RED is integrating into is complex. For example, a complex backend database for specific industry-wide used applications.&lt;/p&gt;
&lt;h3 id=&quot;node-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#node-development&quot;&gt;Node Development&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the core of some integration projects lies a critical requirement: the need for specific integrations that align precisely with your application&#39;s demands. This is where Node-RED&#39;s open-source nature becomes its most significant asset. Node-RED allows for the development of custom nodes, catering to specialized protocols unique to your organization or to serve niche applications. Such node development isn&#39;t just another feature; it represents the foundational element of Node-RED, embodying the platform&#39;s core value proposition.&lt;/p&gt;
&lt;p&gt;Whether addressing the need for custom integration with internal systems or expanding functionality to include less common applications, node development stands as the pivotal mechanism for enabling these capabilities. This critical development can be undertaken in-house, leveraging your team&#39;s expertise, or through PS specialized in node development.&lt;/p&gt;
&lt;h4 id=&quot;conflating-flow-and-node-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#conflating-flow-and-node-development&quot;&gt;Conflating Flow and Node Development&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;It is important when scoping out a project to identify all of the potential nodes needed and identify any potential missing ones. The skills for developing Nodes and Flow development, while similar, are often different skill sets.  Having these identified will help prevent scope creep and setting expectations on timelines.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/02/professional-services-for-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As we&#39;ve explored throughout this article, Professional Services for Node-RED can significantly enhance the efficiency, security, and scalability of your automation and integration projects. From the initial setup and configuration to the intricacies of flow and node development, the expertise PS teams offer can be invaluable. The decision to engage with Professional Services should be informed by your project&#39;s specific needs, internal capabilities, and strategic priorities. Whether it&#39;s leveraging PS for the foundational setup of your Node-RED instance, outsourcing flow development to expedite project timelines, or seeking expert assistance for node development, the goal is the same: create a coding environment that is conducive to citizen development.&lt;/p&gt;
&lt;p&gt;If you are interested in professional services or consultation, &lt;a href=&quot;https://flowfuse.com/professional-services/&quot;&gt;please reach out&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/</id>
        <title>Unified Namespace: When to Use It, and When to Choose Something Else</title>
        <summary>Data isn&#39;t created equal, some data doesn&#39;t fit the UNS</summary>
        <updated>2024-01-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;At FlowFuse, we&#39;re convinced of the Unified Namespace (UNS) architecture for IoT cases. It&#39;s a powerful tool that can make information much more readily available and easy to consume. However, as with any architecture, there are times when it&#39;s not the best choice. In this blog post, we&#39;ll discuss when to use the UNS and when to consider other options.&lt;/p&gt;
&lt;h3 id=&quot;latency-sensitivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/#latency-sensitivity&quot;&gt;Latency sensitivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When automating strictly digital tasks, there&#39;s generally no or very lenient requirements on latency. Requesting APIs from another server, normalizing data, and sending it towards another service takes very little time, though it hardly matters if you’re 100ms later than usual. In industrial automation or other cases where physical safety is safeguarded, there’s a requirement for low latency to ensure that data is transmitted and processed quickly enough to maintain real-time control of processes.&lt;/p&gt;
&lt;p&gt;Extending this beyond the UNS – For controlled use cases, use specialized software and do not rely on third parties to broker the information correctly.&lt;/p&gt;
&lt;p&gt;However, while control was used as an example here, the general case here is not the UNS for real-time, low-latency communication.&lt;/p&gt;
&lt;h3 id=&quot;large-files-or-binary-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/#large-files-or-binary-data&quot;&gt;Large files or binary data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sending large blobs of binary data, such as pictures and archives, through UNS is not recommended due to several drawbacks. First, UNS is optimized for small, mostly text-based communication, and sending binary data through it can significantly increase message size and processing overhead. As the sender of the data, there’s also generally no control over the number of receivers of the data, so if you send a large file to the broker once, it might need to be copied many times for every receiver.&lt;/p&gt;
&lt;p&gt;To overcome these limitations, it is more efficient and practical to store binary data elsewhere, such as on a shared storage location or a cloud service. Once the data is stored externally, a reference to its location can be sent through UNS.&lt;/p&gt;
&lt;h3 id=&quot;data-security-and-data-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/#data-security-and-data-access&quot;&gt;Data security and data access&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The UNS becomes more useful the more hubs are connected, and it stands to reason that better business outcomes are achieved when everything is connected. Not just the sensor data (Level 1 of the &lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#automation-pyramid---visualization&quot;&gt;automation pyramid&lt;/a&gt; &lt;em&gt;except actuators&lt;/em&gt;), but also the customer-facing systems like your ERP (Level 4 or the automation pyramid), and even your CRM, Customer Relationship Management. This would allow better insight and communication with the customer when, for example, their car is done with production and will be shipped to them. The CRM contains personal details about the customer. Publishing what a customer ordered might thus disclose personally identifiable information (PII).&lt;/p&gt;
&lt;p&gt;Connecting a CRM is certainly possible, and could streamline the supply chain, but PII shouldn’t be published. Consider if there’s a unique ID for the customer instead to use. Does your CRM, for example, keep a customer ID? If not, mask the information instead. Use strong hashing algorithms like SHA-512 to hash their email addresses. This way, other systems can cross reference messages received in the UNS, without ever knowing the customer PII. Another venue to explore is topic-based authentication for data receivers, which most data brokers provide. However, stripping and masking PII is still highly recommended either way.&lt;/p&gt;
&lt;h3 id=&quot;in-conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-when-not-to-use/#in-conclusion&quot;&gt;In Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Unified Namespace is a powerful architecture that can make IoT data more accessible and easier to consume. However, it&#39;s not always the best choice for all applications. When considering whether to use the UNS, be sure to weigh the benefits against the potential risks. If you need low latency, strong data security, or fine-grained control over data access, you may need to adjust your architecture pattern or instantiate point-to-point connections through REST or other interfaces.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/</id>
        <title>AI and ChatGPT - Revolutionizing the Manufacturing Industry</title>
        <summary>How AI and Conversational Technologies are Transforming Industrial Processes</summary>
        <updated>2024-01-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The application of artificial intelligence (AI) in various industries, particularly in manufacturing, is a topic of growing interest. The evolution of technologies like ChatGPT is driving significant changes in this sector. For a more nuanced understanding, we reference four informative blog posts from our team members. The first post, &lt;a href=&quot;https://flowfuse.com/blog/2023/12/ai-use-cases/&quot;&gt;&amp;quot;AI Use Cases that are shaping the next manufacturing frontier&amp;quot;&lt;/a&gt;, offers an insightful overview of AI&#39;s role in diverse areas. Following this, &lt;a href=&quot;https://flowfuse.com/blog/2023/11/ai-assistant/&quot;&gt;&amp;quot;ChatGPT AI Assistants with Node-RED&amp;quot;&lt;/a&gt; examines the specific impact of AI assistants. The third article, &lt;a href=&quot;https://flowfuse.com/blog/2023/11/chatgpt-gpt/&quot;&gt;&amp;quot;Node-RED Builder a ChatGPT GPT&amp;quot;&lt;/a&gt;, discusses the capabilities of generative pre-trained transformers like ChatGPT. Lastly, &lt;a href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/&quot;&gt;&amp;quot;How ChatGPT improves Node-RED Developer Experience&amp;quot;&lt;/a&gt; explores ChatGPT&#39;s application in Node-RED development, an important aspect for many in manufacturing.&lt;/p&gt;
&lt;h2 id=&quot;how-ai-and-chatgpt-are-impacting-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#how-ai-and-chatgpt-are-impacting-manufacturing&quot;&gt;How AI and ChatGPT are Impacting Manufacturing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AI and ChatGPT&#39;s integration into manufacturing indicates a shift in production process management. Here are some key impacts:&lt;/p&gt;
&lt;h3 id=&quot;boosting-efficiency-and-productivity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#boosting-efficiency-and-productivity&quot;&gt;Boosting Efficiency and Productivity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI, especially ChatGPT, enhances manufacturing efficiency by analyzing data to improve production lines, predict maintenance, and aid in design and development.&lt;/p&gt;
&lt;h3 id=&quot;automating-routine-tasks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#automating-routine-tasks&quot;&gt;Automating Routine Tasks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI is adept at handling repetitive tasks, speeding up manufacturing and allowing human workers to engage in more complex production aspects.&lt;/p&gt;
&lt;h3 id=&quot;elevating-quality-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#elevating-quality-control&quot;&gt;Elevating Quality Control&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI algorithms consistently ensure high-quality standards, quickly identifying and fixing product defects or deviations.&lt;/p&gt;
&lt;h3 id=&quot;enabling-customization-and-flexibility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#enabling-customization-and-flexibility&quot;&gt;Enabling Customization and Flexibility&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI&#39;s learning and adaptability make it suitable for customizing production, allowing manufacturers to meet specific customer demands more efficiently.&lt;/p&gt;
&lt;h3 id=&quot;transforming-the-workforce&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#transforming-the-workforce&quot;&gt;Transforming the Workforce&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AI in manufacturing necessitates skilled workers to operate and maintain these systems, altering job roles and responsibilities.&lt;/p&gt;
&lt;h2 id=&quot;pros-and-cons-of-ai-and-chatgpt-in-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#pros-and-cons-of-ai-and-chatgpt-in-manufacturing&quot;&gt;Pros and Cons of AI and ChatGPT in Manufacturing&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#pros&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Boosted Productivity: AI-driven automation increases production efficiency.&lt;/li&gt;
&lt;li&gt;Consistent Quality Assurance: AI ensures ongoing product quality.&lt;/li&gt;
&lt;li&gt;Reduced Costs: AI optimizes resource use and minimizes waste.&lt;/li&gt;
&lt;li&gt;Encouraging Innovation: AI facilitates new manufacturing methods and products.&lt;/li&gt;
&lt;li&gt;Enhancing Safety: AI reduces human exposure to hazardous manufacturing conditions.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#cons&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Initial Investment Costs: AI technology implementation can be expensive.&lt;/li&gt;
&lt;li&gt;Need for Skilled Labor: Demand for workers proficient in AI technologies is growing.&lt;/li&gt;
&lt;li&gt;Job Role Changes: Automation might decrease the need for certain labor roles.&lt;/li&gt;
&lt;li&gt;Security Concerns: AI systems can be susceptible to cyber threats.&lt;/li&gt;
&lt;li&gt;Technological Dependence: Excessive reliance on AI could limit problem-solving abilities in workers.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;frequently-asked-questions-(faqs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/revolutionizing-manufacturing-impact-ai-chatgpt-technologies/#frequently-asked-questions-(faqs)&quot;&gt;Frequently Asked Questions (FAQs)&lt;/a&gt;&lt;/h2&gt;
&lt;details&gt;
&lt;summary&gt;1. How is AI changing manufacturing?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;AI is altering manufacturing through automation, optimizing efficiency, and fostering production innovations.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;2. What is ChatGPT&#39;s role in manufacturing?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;ChatGPT aids in data analysis, automates processes, and improves communication and documentation in manufacturing.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;3. Are manufacturing jobs at risk due to AI?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;While AI may automate some repetitive jobs, it also creates opportunities for skilled labor in technology management and development.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;4. Can AI enhance manufacturing product quality?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;Yes, AI&#39;s continuous monitoring and analysis significantly boost quality control.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;5. What are the main challenges of integrating AI in manufacturing?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;Challenges include high implementation costs, the need for skilled labor, and transitioning to automated processes.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;6. Is AI cost-effective in manufacturing?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;Despite high initial costs, AI can lead to long-term savings through improved efficiency and waste reduction.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;7. How does AI affect manufacturing worker safety?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;AI reduces risk by taking over hazardous tasks, improving overall workplace safety.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;8. Can small manufacturers benefit from AI?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;Yes, AI solutions are increasingly accessible for small-scale manufacturers.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;9. What training is required for AI-enabled manufacturing workers?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;Training in AI system operation, data analysis, and potentially programming skills is needed.&lt;/strong&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;10. What does the future hold for AI in manufacturing?&lt;/summary&gt;
&lt;br /&gt;
&lt;strong&gt;The future suggests more integrated, intelligent, and adaptable manufacturing processes driven by AI advancements.&lt;/strong&gt;
&lt;/details&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/</id>
        <title>Step-by-Step Guide to Deploying Node-RED with FlowFuse in balenaCloud</title>
        <summary>Fleet management made easier with FlowFuse and balena.</summary>
        <updated>2024-01-30T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;In a &lt;a href=&quot;https://flowfuse.com/webinars/2024/balena/&quot;&gt;recent webinar with balena&lt;/a&gt;, we explored the dynamic capabilities of deploying FlowFuse to a fleet of devices using &lt;a href=&quot;https://www.balena.io/cloud&quot;&gt;balenaCloud&lt;/a&gt;. This blog post serves as a practical guide to replicate that process, specifically tailored for those aiming to streamline their deployment of FlowFuse in an efficient and user-friendly manner.&lt;/p&gt;
&lt;h2 id=&quot;how-to-implement-flowfuse-with-balenacloud-on-a-fleet-of-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#how-to-implement-flowfuse-with-balenacloud-on-a-fleet-of-devices&quot;&gt;How to Implement FlowFuse with balenaCloud on a Fleet of devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cKFu1ljUlKE&quot; title=&quot;Deploying Node-RED with FlowFuse in balenaCloud&quot;&gt;&lt;img alt=&quot;Deploying Node-RED with FlowFuse in balenaCloud&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://i.ytimg.com/vi/cKFu1ljUlKE/hqdefault.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;preparation-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#preparation-steps&quot;&gt;Preparation Steps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before diving into the deployment process, it&#39;s crucial to familiarize yourself with key resources. We recommend reviewing our previous &lt;a href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/&quot;&gt;blog post&lt;/a&gt; on deploying the FlowFuse Device Agent via balena. This post contains a vital link to the GitHub repository, essential for deploying FlowFuse with balena, laying the groundwork for the steps ahead.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-new-fleet-in-balenacloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#creating-a-new-fleet-in-balenacloud&quot;&gt;Creating a New Fleet in balenaCloud&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;a href=&quot;https://github.com/FlowFuse/balena-device-agent&quot;&gt;FlowFuse git&lt;/a&gt; repository. Click on the &lt;strong&gt;Deploy with balena&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Name your fleet.&lt;/li&gt;
&lt;li&gt;Select your default device.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create and Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;adding-devices-to-the-fleet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#adding-devices-to-the-fleet&quot;&gt;Adding Devices to the Fleet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your fleet is created, the next step is to add devices. To add a device to your fleet, follow these &lt;a href=&quot;https://docs.balena.io/learn/getting-started/var-som-mx6/rust/#add-a-device-and-download-os&quot;&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#setting-up-flowfuse&quot;&gt;Setting Up FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Setting up FlowFuse correctly is essential for seamless operation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new instance within FlowFuse or use an existing one if you prefer. Follow these &lt;a href=&quot;https://flowfuse.com/docs/user/introduction/#creating-a-node-red-instance&quot;&gt;instructions&lt;/a&gt; to create a new instance.&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;Device Provisioning Token&lt;/strong&gt; by following these &lt;a href=&quot;https://flowfuse.com/docs/device-agent/register/#bulk-registration&quot;&gt;instructions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ensure you add the FlowFuse Node-RED application you want the devices to provision. If left at default, devices will need to be manually added to applications.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;using-the-device-provisioning-token&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#using-the-device-provisioning-token&quot;&gt;Using the Device Provisioning Token&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;First, convert the contents of the Device Provisioning Token to base64. Follow these &lt;a href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#environment-variable&quot;&gt;instructions&lt;/a&gt; to convert the file to base64.&lt;/li&gt;
&lt;li&gt;Once converted, import this string into balena as a &lt;strong&gt;Fleet&lt;/strong&gt; level variable, not a device level variable. Follow these &lt;a href=&quot;https://docs.balena.io/learn/manage/variables/#fleet-wide-variables&quot;&gt;instructions&lt;/a&gt; to import the Fleet level variable with the Name &lt;code&gt;FF_DEVICE_YML&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This action will provision any new device added to the fleet with the yaml file configuration, automatically adding the device to a FlowFuse instance.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;deploying-and-testing-the-flowfuse-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#deploying-and-testing-the-flowfuse-instance&quot;&gt;Deploying and Testing the FlowFuse Instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deploying the FlowFuse instance brings everything together:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your FlowFuse application created earlier.&lt;/li&gt;
&lt;li&gt;Go to your devices and you should now see your newly provisioned devices from balena.&lt;/li&gt;
&lt;li&gt;If this is your first time setting up your fleet, the device will not have a snapshot. You will need to deploy a snapshot. Follow these &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/#create-a-snapshot&quot;&gt;instructions&lt;/a&gt; to do so. Ensure that you select &lt;strong&gt;Set Target Snapshot&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Once complete, the FlowFuse instance will deploy to your device(s).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;integrating-influxdb-(optional)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#integrating-influxdb-(optional)&quot;&gt;Integrating InfluxDB (Optional)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating InfluxDB enables effective data storage and management:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Similar to the previous steps, navigate to this &lt;a href=&quot;https://github.com/mpous/flowfuse-agent-influx-balena/tree/main?tab=readme-ov-file&quot;&gt;Github repository&lt;/a&gt; and click &lt;strong&gt;Deploy with balena&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This time, instead of creating a new fleet, select &lt;strong&gt;Use an existing fleet instead&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose your fleet for deployment and select &lt;strong&gt;Deploy to fleet&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;data-generation-and-management&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#data-generation-and-management&quot;&gt;Data Generation and Management&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For testing, we have created a flow to get you started. Follow this &lt;a href=&quot;https://flows.nodered.org/flow/66f37bb739b6cdb0c7ad3a4e2edd68ef&quot;&gt;link&lt;/a&gt; and import it. There are four sets of flows for you to begin with. The first is for data generation. The second is a manual data generation flow. The third is key as it initiates the creation of a database, in this case, &lt;strong&gt;mydb&lt;/strong&gt;. The last flow is a simple query that pulls data from InfluxDB.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the flows into your FlowFuse instance of Node-RED and deploy. Follow these &lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#2.-import-helpful-example-flows-provided-with-custom-nodes&quot;&gt;instructions&lt;/a&gt; for importing and exporting.&lt;/li&gt;
&lt;li&gt;Return to Flowfuse, go to your instance, and create another &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/#create-a-snapshot&quot;&gt;snapshot&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ensure that you &lt;strong&gt;Set Target Snapshot&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;finalizing-and-testing-the-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#finalizing-and-testing-the-setup&quot;&gt;Finalizing and Testing the Setup&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The final steps ensure that your setup is fully operational:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Once deployed, navigate to the device.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/device-agent/deploy/#editing-the-node-red-flows-on-a-remote-instance-that-is-assigned-to-an-application&quot;&gt;Enable Developer Mode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Next, click the newly revealed button, &lt;strong&gt;Open Editor&lt;/strong&gt;, to access the deployed Flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/how-to-deploy-node-red-with-flowfuse-to-balenacloud/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Implementing FlowFuse with balenaCloud significantly enhances your device management and data processing capabilities. This guide provides a foundational approach, but don&#39;t hesitate to delve deeper into each step to tailor the setup to your specific needs.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/</id>
        <title>Speech-Driven Chatbot System with Node-RED</title>
        <summary>Guide to building speech-driven chatbot using Node-RED, speech recognition, and Dashboard 2.0.</summary>
        <updated>2024-01-29T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever wanted to integrate speech recognition and synthesis into your Node-RED project and thought it was too complex? Often it has required external services or APIs. However, in this guide, we show you how you can use speech recognition and synthesis in your Node-RED projects without needing an external service or API.&lt;/p&gt;
&lt;p&gt;In addition, we make things more interesting by building a system that can listen to us and respond like humans using the Chat-GPT API.
Let&#39;s get started!&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-speech-recognition-and-synthesis%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#what-exactly-is-speech-recognition-and-synthesis%3F&quot;&gt;What exactly is speech recognition and synthesis?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Speech recognition is a technology where a device captures spoken words through a microphone, checks against grammar rules and vocabulary, and returns recognized words as text. On the other hand, speech synthesis converts app text into speech and plays it through a device&#39;s speaker or audio output. There are many benefits and real-world applications of this technology.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hands-Free Operation:&lt;/strong&gt; Using speech recognition technology is often used today to perform tasks such as making calls, sending messages, or controlling smart home devices without the need for physical interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility:&lt;/strong&gt; It allows individuals with visual impairments to access digital content through spoken words and as discussed above, to control devices without physical interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efficient Content Consumption:&lt;/strong&gt; It allows us to listen to information instead of reading. For example, in the audiobook industry by using speech synthesis technology they create audio versions of books which helps users to be more productive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;installing-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#installing-dashboard-2.0&quot;&gt;Installing Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Install Dashboard 2.0. Follow these &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;instructions&lt;/a&gt; to get up and running.&lt;/p&gt;
&lt;h2 id=&quot;building-speech-to-text-vue-component&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#building-speech-to-text-vue-component&quot;&gt;Building Speech-to-Text Vue component&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will build a Vue component that will perform a speech-to-text conversion operation using Web speech API, and display results on the dashboard.  While we did say previously that we won&#39;t need any external API for speech recognition, this &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API&quot;&gt;Web Speech API&lt;/a&gt; is not an external API.
This will process your speech locally as it is a JavaScript API that allows us to use speech-related functionalities, such as speech recognition and synthesis, in a web browser directly. It is widely present in modern browsers (except Firefox) which eliminates the need for external APIs to implement these features. Let&#39;s now start to build that component.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a ui template widget to canvas and select the created group.&lt;/li&gt;
&lt;li&gt;Paste the below Vue snippets into the template widget step by step.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you are unfamiliar with Vue, we have added comments that will help you to understand the code better.&lt;/p&gt;
&lt;p&gt;We are going to start by pasting a user interface’s snippet which will allow us to interact with our system. This snippet adds a button that triggers our system to listen, an Icon, and a paragraph to display speech recognition results on the dashboard.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-59&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-59&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;flex-direction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; column&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Button triggers recording when clicked --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;@click&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;startRecording&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Microphone icon inside the button --&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Microphone&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 62px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 62px&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;microphoneIcon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Displaying speech recognition results --&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;You:&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; {{ results }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-59&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Now paste the below script right after the HTML in the template widget, This script adds functionality of speech recognition in our system.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-63&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-63&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token comment&quot;&gt;// Initial data properties&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;buttonText&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Speak&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;microphoneIcon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;http://icons.iconarchive.com/icons/blackvariant/button-ui-requests-15/512/Microphone-icon.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;recognition&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token literal-property property&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to start recording&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;startRecording&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buttonText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Recording&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to process the speech recognition results&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;processSpeech&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;   result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transcript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; results&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;speak&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token comment&quot;&gt;//Sending result to next node as payload&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to handle the start of recognition&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;handleRecognitionStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;microphoneIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://upload.wikimedia.org/wikipedia/commons/0/06/Mic-Animation.gif&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to handle recognition errors&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;handleRecognitionError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;microphoneIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;no-speech&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;audio-capture&#39;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://i.ytimg.com/vi/9YQU797Oy0Y/hqdefault.jpg&#39;&lt;/span&gt;&lt;br /&gt;       &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;microphoneIcon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to handle the end of recognition&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;handleRecognitionEnd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;microphoneIcon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;http://icons.iconarchive.com/icons/blackvariant/button-ui-requests-15/512/Microphone-icon.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Method to set up the SpeechRecognition object&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token function&quot;&gt;setupRecognition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;webkitSpeechRecognition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;continuous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interimResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onresult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;processSpeech&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onstart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleRecognitionStart&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onerror &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleRecognitionError&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recognition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onend &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleRecognitionEnd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token comment&quot;&gt;// Initialize SpeechRecognition when the component is mounted&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setupRecognition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-63&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;adding-an-environment-variable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#adding-an-environment-variable&quot;&gt;Adding an Environment variable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Why do we need to add an environment variable? In this guide, we will build a speech-driven chatbot that involves integrating the Chat-GPT AI model. For this we need openAi’s API key. An API key is a form of private data that needs to be protected from being exposed. That is why we need the environment variables. It provides a secure way to store and access the API key without revealing it directly in the flow.  For more details see &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Using Environment Variables in Node-RED&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the instance&#39;s setting and then go to the environment section.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;add variable&lt;/code&gt; button and add a variable for Chat-gpt API.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Setting environment variable for chat-gpt token&quot; alt=&quot;&amp;quot;Setting environment variable for Chat-gpt token&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/speech-driven-chatbot-environment-section.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting-msg-property&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#setting-msg-property&quot;&gt;Setting msg property&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let’s set that added environment variables as msg&#39;s property.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a change node to canvas.&lt;/li&gt;
&lt;li&gt;Set environment variable to ms.token property.&lt;/li&gt;
&lt;li&gt;Connect the change node’s input to the template widget’s output.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Setting msg&#39;s property for Chat-gpt token&quot; alt=&quot;&amp;quot;Setting msg&#39;s property for Chat-gpt token&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/speech-driven-chatbot-change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;installing-and-configuring-custom-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#installing-and-configuring-custom-node&quot;&gt;Installing and configuring custom node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this section, we will install a custom node that will allow us to interact with the Chat-gpt AI model.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;@sumit_shinde_84/node-red-contrib-node-gpt&lt;/code&gt; by pallet manager, you can use other nodes according to your preference.&lt;/li&gt;
&lt;li&gt;Drag a ChatGPT node to canvas.&lt;/li&gt;
&lt;li&gt;Connect the ChatGPT node’s input to the change node’s output.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;building-text-to-speech-vue-component&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#building-text-to-speech-vue-component&quot;&gt;Building Text-to-Speech Vue component&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We will build a Vue component that converts text received from ChatGPT into speech.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another template widget to canvas and select the added group, alternatively, you can create a separate group for this component according to your preference.&lt;/li&gt;
&lt;li&gt;Paste the below Vue snippets into the template widget.&lt;/li&gt;
&lt;li&gt;Connect the template widget’s input to the ChatGPT node’s output.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Paste the below snippet in the template widget which displays chat-gpt response on the dashboard&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-160&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-160&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Chat-gpt: &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; {{textToSpeech}}&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-160&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Paste the below snippet right after the HTML, This snippet adds the functionality of text-to-speech into our system, which triggers when msg received by the previous node.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-164&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-164&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Data property to store the text to be spoken&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;textToSpeech&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Method to trigger text-to-speech&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;speakText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Check if there is non-empty text to speech&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textToSpeech&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Create a SpeechSynthesisUtterance with the text to be spoken&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; utterance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;  &lt;span class=&quot;token class-name&quot;&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textToSpeech&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Use the SpeechSynthesis API to speak the provided text&lt;/span&gt;&lt;br /&gt;        window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;speechSynthesis&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;speak&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;utterance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Event listener for receiving messages    &lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;msg-input:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Update the textToSpeech property with the received message payload&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textToSpeech &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Trigger text-to-speech with the received message&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;speakText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;textarea&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-164&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Your final flow should look like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Speech Driven Chatbot system flow&quot; alt=&quot;&amp;quot;Speech Driven Chatbot system flow&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/speech-driven-chatbot-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#deploying-the-flow&quot;&gt;Deploying the Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Deploying Sentiment analysis Node-RED flow&quot; alt=&quot;&amp;quot;Deploying Sentiment analysis Node-RED flow&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/speech-driven-chatbot-flowfue-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We have successfully built our Speech-Driven Chatbot System. Now it&#39;s time to deploy the flow, to do that click on the red deploy button which you can find in the top right corner. After that go to &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Speech Driven Chatbot using Node-RED Dashboard 2.0&quot; alt=&quot;&amp;quot;Speech Driven Chatbot using Node-RED Dashboard 2.0&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/speech-driven-chatbot-system.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/speech-driven-chatbot-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this guide, we have built a Speech-Driven Chatbot System which allows us to understand how we can add speech recognition and synthesis features into our project without any external API or custom node. It also provides a brief overview of how we can integrate chat-gpt into our system.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/</id>
        <title>Personalised Multi-user Dashboards with Node-RED Dashboard 2.0!</title>
        <summary>Explore how to build multi-user Dashboards, secured with FlowFuse Cloud!</summary>
        <updated>2024-01-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This week has seen the release of the &lt;a href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-ga/&quot;&gt;first major version of Node-RED Dashboard 2.0&lt;/a&gt;, with it, we&#39;ve made available a new FlowFuse-exclusive feature, personalised multi-user dashboards.&lt;/p&gt;
&lt;p&gt;This new feature will allow you to build applications that provide unique data to each user, build admin-only views, and track user activity, to name but a few. We&#39;re really excited to see what the Node-RED Community and our FlowFuse customers can do with such a powerful and flexible framework.&lt;/p&gt;
&lt;h2 id=&quot;personalised-multi-user-dashboards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#personalised-multi-user-dashboards&quot;&gt;Personalised Multi User Dashboards&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The original Node-RED Dashboard was built with a &amp;quot;single source of truth&amp;quot;, no matter how many users interacted with the dashboard, each user would always see the same data. This is great for prototyping, or hobby projects, but as you scale up your Node-RED usage, you&#39;ll want to be able to have unique dashboard experiences for each user.&lt;/p&gt;
&lt;h3 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To enable personalised multi-user dashboards, you&#39;ll need to be using FlowFuse, and complete two steps:&lt;/p&gt;
&lt;h4 id=&quot;step-1%3A-enable-%22flowfuse-user-authentication%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#step-1%3A-enable-%22flowfuse-user-authentication%22&quot;&gt;Step 1: Enable &amp;quot;FlowFuse User Authentication&amp;quot;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;All instances on FlowFuse can be configured with &lt;em&gt;&amp;quot;FlowFuse User Authentication&amp;quot;&lt;/em&gt; in the &amp;quot;Security&amp;quot; Settings. This option requires any user that wants access to your Editor or dashboard to be authorized by FlowFuse first.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Screenshot of the &#39;Security&#39; settings available for any Instances running in FlowFuse&quot; alt=&quot;&amp;quot;Screenshot of the &#39;Security&#39; settings available for any Instances running in FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-ffauth.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 mb-4 text-center&quot;&gt;&lt;b&gt;&quot;Screenshot of the &#39;Security&#39; settings available for any Instances running in FlowFuse&quot;&lt;/b&gt;&lt;/figcaption&gt;
&lt;h4 id=&quot;step-2%3A-install-flowfuse&#39;s-user-addon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#step-2%3A-install-flowfuse&#39;s-user-addon&quot;&gt;Step 2: Install FlowFuse&#39;s User Addon&lt;/a&gt;&lt;/h4&gt;
&lt;h5 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Note: Every instance created from today onwards automatically comes with the necessary configuration. Already created instances need to be manually restarted.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Personalised Multi-User Dashboard plugin, &lt;code&gt;@flowfuse/node-red-dashboard-2-user-addon&lt;/code&gt;, is available in our &lt;a href=&quot;https://flowfuse.com/certified-nodes/&quot;&gt;Certified Nodes&lt;/a&gt; catalogue, accessible to our Teams and Enterprise customers.&lt;/p&gt;
&lt;p&gt;Once the &amp;quot;FlowFuse User Authentication&amp;quot; option has been enabled on your instance, you can then install our plugin, &lt;code&gt;@flowfuse/node-red-dashboard-2-user-addon&lt;/code&gt;, through the &amp;quot;Manage Palette&amp;quot; option in the Node-RED Editor.&lt;/p&gt;
&lt;p&gt;For your devices, we provide the necessary configuration and access token upon request, so that your Node-RED devices can also benefit from a Personalised Multi-user Dashboard.&lt;/p&gt;
&lt;h5 id=&quot;flowfuse-self-hosted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#flowfuse-self-hosted&quot;&gt;FlowFuse Self-Hosted&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;For all our Teams and Enterprise Self-Hosted customers who also want to use the Certified Nodes and the Multi-User Dashboard, we provide all necessary configurations upon request to get started.&lt;/p&gt;
&lt;p&gt;Alternatively, if you&#39;re looking to elevate your Node-RED infrastructure, &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;book in a chat with us&lt;/a&gt; to talk about how FlowFuse can help.&lt;/p&gt;
&lt;h3 id=&quot;using-the-plugin&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#using-the-plugin&quot;&gt;Using the Plugin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once enabled, any messages emitted by a Dashboard 2.0 node will contain a new &lt;code&gt;msg._client.user&lt;/code&gt; object, e.g:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-61&quot;&gt;
  &lt;pre class=&quot;language-js&quot;&gt;&lt;code id=&quot;code-61&quot; class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// unique identifier for the user&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// FlowFuse Username&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;// E-Mail Address connected to their FlowFuse account&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;// Full Name&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;// User Avatar from FlowFuse&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-61&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Then, when running Node-RED Dashboard 2.0 on FlowFuse, you&#39;ll have a new sidebar option in the Node-RED Editor, which allows you to control which node types allow for &amp;quot;client constraints&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;The new &#39;FF Auth&#39; options available in Node-RED to allow for client constraints&quot; alt=&quot;The new &#39;FF Auth&#39; options available in Node-RED to allow for client constraints&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-ff-settings.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 mb-4 text-center&quot;&gt;&lt;b&gt;A screenshot of the new &#39;FF Auth&#39; options available in Node-RED to allow for client constraints on different node types.&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;In the original Node-RED Dashboard, this was &lt;em&gt;always&lt;/em&gt; enabled for the &lt;code&gt;ui-notification&lt;/code&gt; and &lt;code&gt;ui-control&lt;/code&gt; nodes, whereby you could include &lt;code&gt;msg.socket&lt;/code&gt; data and it would only then send that message to the specified client. For Dashboard 2.0 we&#39;ve extended this concept so that as a Node-RED Developer, you can now include &lt;code&gt;msg._client.user&lt;/code&gt; data in any message sent to a Dashboard 2.0 node. Under the covers, our FlowFuse-exclusive plugin will then automatically filter messages to only send to the relevant user&#39;s connection.&lt;/p&gt;
&lt;p&gt;Utilising this feature, below you can see an example where we send data to a &lt;code&gt;ui-template&lt;/code&gt; to render a custom table for each user. Under the covers this is a &lt;code&gt;ui-event&lt;/code&gt; node (triggered on a page view), which then uses the &lt;code&gt;msg._client.user&lt;/code&gt; object to make a REST API call to retrieve a list of todo items for that specific user. We then wire the response into the &lt;code&gt;ui-template&lt;/code&gt;, which has been configured to &amp;quot;Accept Client Constraints&amp;quot;, and so only sends this data to User 2&#39;s dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Showing Admin Task View&quot; alt=&quot;Showing Admin Task View&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-admin-tasks.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 mb-4 text-center&quot;&gt;&lt;b&gt;Example of a dashboard that displays user-specific content.&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;Note too that we&#39;re also utilising the new &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#teleports&quot;&gt;Teleport&lt;/a&gt; option available in a &lt;code&gt;ui-template&lt;/code&gt; which allows us to define content to show in the top-right of the dashboard, in this case, a little &lt;em&gt;&amp;quot;Hi {username}&amp;quot;&lt;/em&gt; message.&lt;/p&gt;
&lt;h3 id=&quot;examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#examples&quot;&gt;Examples&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;rendering-logged-in-user-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#rendering-logged-in-user-data&quot;&gt;Rendering Logged In User Data&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In the previous example, you may have noticed that we&#39;re also displaying a welcome to the authenticated user on our dashboard, this means that we have access to the full User object within any &lt;code&gt;ui-template&lt;/code&gt; that we render too.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Showing User Unique Data&quot; alt=&quot;Showing User Unique Data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-user2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 mb-4 text-center&quot;&gt;&lt;b&gt;The &quot;Admin&quot; view that is only made available to users registered as an &quot;admin&quot;.&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;Under the covers, we&#39;re appending our &lt;code&gt;user&lt;/code&gt; object to the &lt;code&gt;msg&lt;/code&gt; object, via the SocketIO &lt;code&gt;auth&lt;/code&gt; option. We make the &lt;code&gt;socketio&lt;/code&gt; object available via a computed &lt;code&gt;setup&lt;/code&gt; variable, this means that we can access this data in any &lt;code&gt;ui-template&lt;/code&gt; node, and render like so:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-98&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-98&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hi, {{ setup?.socketio?.auth?.user?.name }}!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-98&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;To enable custom user-by-user content in a &lt;code&gt;ui-template&lt;/code&gt; though, we must allow it to &amp;quot;Accept Client Constraints&amp;quot;. This means that if a &lt;code&gt;.msg._client.user&lt;/code&gt; value is included in any messages sent to a &lt;code&gt;ui-template&lt;/code&gt; node, then the underlying SocketIO message will be filtered to only send to the relevant user&#39;s connection, and no others.&lt;/p&gt;
&lt;h4 id=&quot;admin-only-views&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#admin-only-views&quot;&gt;Admin Only Views&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;With this new functionality we can also now show/hide content based on the authenticated user.&lt;/p&gt;
&lt;p&gt;We recently introduced the option to &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/484&quot;&gt;set default visiblity &amp;amp; interaction states&lt;/a&gt;. This was partly introduced because it&#39;s a good practice to set the default &amp;quot;Visibility&amp;quot; option for any admin-only pages to &amp;quot;Hidden&amp;quot;, and then use a &lt;code&gt;ui-control&lt;/code&gt; node to show the content only to the relevant admins.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;100%&quot; src=&quot;https://flows.nodered.org/flow/2fe8e6f1e7002f1ff6a9195ad1a153b6/share&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none; margin-bottom: 12px;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Let&#39;s breakdown the above flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We wire a &lt;code&gt;ui-event&lt;/code&gt; node (which emits each time a user views a page) into a switch node&lt;/li&gt;
&lt;li&gt;Our switch node checks the &lt;code&gt;user.username&lt;/code&gt; against a known list of admin users and branches &amp;quot;admin:&amp;quot; and &amp;quot;non-admin&amp;quot; users&lt;/li&gt;
&lt;li&gt;For admin users, the &lt;code&gt;change&lt;/code&gt; node defines a message for our &lt;code&gt;ui-control&lt;/code&gt; node to dynamically show content, in this case an &amp;quot;Admin&amp;quot; page, when appropriate.&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-132&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-132&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;pages&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Admin View&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-132&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;All events going into &lt;code&gt;ui-control&lt;/code&gt; are automatically filtered based on the &lt;code&gt;msg._client.user&lt;/code&gt; object, so only the Admin users will receive the message to show the &amp;quot;Admin View&amp;quot; page, resulting in:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; title=&quot;Showing Admin Only View&quot; alt=&quot;Showing Admin Only View&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-admin.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 mb-4 text-center&quot;&gt;&lt;b&gt;The &quot;Admin&quot; view that is only made available to users registered as an &quot;admin&quot;.&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;Further extensions of this could also check &lt;code&gt;ui-event&lt;/code&gt; in case a non-admin user tries to access the &lt;code&gt;/admin&lt;/code&gt; page directly, in which case we can utilise &lt;code&gt;ui-control&lt;/code&gt; to navigate the user away from the page immediately. See the &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-control.html#navigation&quot;&gt;ui-control documentation&lt;/a&gt; for more details on this.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-webinar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#upcoming-webinar&quot;&gt;Upcoming Webinar&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in learning more about Dashboard 2.0 and in particular multi-user Dashboards, we&#39;re hosting a webinar on Thursday, 29th February. You can find out more information &lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We aren&#39;t stopping here, we&#39;ll continue to push Dashboard 2.0 forward with future development, and you can track that progress on our GitHub Projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/5&quot;&gt;Dashboard 1.0 Feature Parity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/dashboard-2-ga/</id>
        <title>Node-RED Dashboard 2.0 is Generally Available!</title>
        <summary>This week sees our first major version release of Node-RED Dashboard 2.0!</summary>
        <updated>2024-01-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/dashboard-2-ga/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Back in &lt;a href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/&quot;&gt;June 2023&lt;/a&gt; we announced that FlowFuse would be investing into building out the next generation of Node-RED Dashboard, the most popular UI framework for Node-RED.
We followed this up with the &lt;a href=&quot;https://flowfuse.com/blog/2023/07/dashboard-0-1-release/&quot;&gt;first release&lt;/a&gt; (&lt;code&gt;0.0.1&lt;/code&gt;) in July, just one month later, and today, we are pleased to announce that we have reached a major milestone in this journey, with the release of our first major version (&lt;code&gt;1.0.0&lt;/code&gt;) of Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Dashboard 2.0 Example showing weather data&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-ga-example.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With our &lt;code&gt;1.0.0&lt;/code&gt; release, you can now build your dashboards on a reliable and stable package, and we invite you to to start contributing your own third-party &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/widgets/third-party.html&quot;&gt;widgets&lt;/a&gt; and &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/plugins/&quot;&gt;plugins&lt;/a&gt;. We&#39;re excited to see what the community can contribute and build on top of this new Dashboard 2.0 framework, and we&#39;ll be continuing development to the core collection of widgets too.&lt;/p&gt;
&lt;p&gt;With Node-RED Dashboard 2.0, we have re-built the original Node-RED Dashboard from the ground up. It is now extensible due to it being VueJS-based, completely responsive down to mobile, and we&#39;ve made many quality of life improvements across the board to the existing widget collection, as well as adding a few new ones too.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-new-in-dashboard-2.0%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-ga/#what&#39;s-new-in-dashboard-2.0%3F&quot;&gt;What&#39;s new in Dashboard 2.0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve shared plenty of updates since we started, detailing the feature parity with the original Node-RED Dashboard, as well as some of the new widgets and features we&#39;ve added to the new Dashboard, such as Markdown, Mermaid Charts and new Layout Options, you can read more about those here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/&quot;&gt;Dynamic Markdown, Tables &amp;amp; Notebooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/&quot;&gt;UI Chart Improvements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/&quot;&gt;Building a Custom Video Player&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, the most requested feature for the legacy dashboard has been implemented in Dashboard 2.0, the ability to hide charts and forms based on the user that&#39;s viewing the dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Dashboard 2.0 Example showing personalised dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/multi-user-dashboard-user2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Read more about it here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-multi-user/&quot;&gt;Personalised Multi User Dashboards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If that wasn&#39;t enough, we also have &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;rich documentation&lt;/a&gt; for Dashboard 2.0 too, detailing all of the available nodes, details on how Dashboard 2.0 is built and how to contribute to the project too if you&#39;re that way inclined.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-webinar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-ga/#upcoming-webinar&quot;&gt;Upcoming Webinar&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in learning more about Dashboard 2.0 and in particular, personalised multi-user dashboards, we&#39;re hosting a webinar on Thursday, 29th February. You can find out more information &lt;a href=&quot;https://flowfuse.com/webinars/2024/node-red-dashboard-multi-user/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/dashboard-2-ga/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We aren&#39;t stopping here, we&#39;ll continnue to push Dashboard 2.0 forward with future development, with a &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/12&quot;&gt;new UI Gauge&lt;/a&gt; next on the list. You can track that progress of that particular issue, and the rest of the work we have lined up on our GitHub Projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/5&quot;&gt;Dashboard 1.0 Feature Parity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/</id>
        <title>Sentiment Analysis with Node-RED</title>
        <summary>A guide to building a simple sentiment analysis system with Node-RED.</summary>
        <updated>2024-01-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/"/>
        <author><name>Sumit Shinde</name></author>
        <content type="html">&lt;p&gt;Have you ever built a sentiment analysis system to extract insights from text content? If yes then I don’t think you&#39;ll need an explanation of how complex it is to build. In this guide, we will build a sentiment analysis system with Node-RED using Dashboard 2.0 in a few easy steps.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-sentiment-analysis%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#what-exactly-is-sentiment-analysis%3F&quot;&gt;What exactly is sentiment analysis?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sentiment analysis is a context-mining technique used to understand emotions and opinions expressed in text, often classifying them as positive, neutral, or negative. There are many real-world applications of this technique.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Analysing Feedback:&lt;/strong&gt; Customers, or other stakeholders like employees, are periodically requested to fill out a feedback form. Analysis of such feedback is the most widespread application of sentiment analysis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Campaign Monitoring:&lt;/strong&gt; Another use case of sentiment analysis is a measure of influence which is crucial in any marketing campaign.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brand Monitoring:&lt;/strong&gt; Brand monitoring is another great use case for sentiment analysis. Companies can use sentiment analysis to check the social media sentiments around their brand from their audience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-a-form-in-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#building-a-form-in-dashboard-2.0&quot;&gt;Building a Form in Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this system, we will analyse the sentiment of text content obtained from the user.  For this we are going to build a user interface using Dashboard 2.0 and Node-RED.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Node-RED Dashboard 2.0. Follow these &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;instructions&lt;/a&gt; to install.&lt;/li&gt;
&lt;li&gt;Drag a ui form widget to the canvas and select the created group.&lt;/li&gt;
&lt;li&gt;Add an element in the form widget and give it a name and label, select the type as multiline, and set the number of rows according to your need.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Taking user input for Sentiment analysis using form&quot; alt=&quot;&amp;quot;Taking user input for Sentiment analysis using form&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiment-analysis-form.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;normalizing-the-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#normalizing-the-data&quot;&gt;Normalizing the data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We need to normalize the payload before sending it to the next node because the form widget always returns an object containing the property of values of form elements.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a change node to canvas.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;msg.payload.$FORM_ELEMENT_NAME&lt;/code&gt; to &lt;code&gt;msg.payload&lt;/code&gt;, replace the &lt;code&gt;$FORM_ELEMENT_NAME&lt;/code&gt; with the name of the form element that you have added to the form to obtain user input.&lt;/li&gt;
&lt;li&gt;Connect the UI form nodes output to the change node’s input.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Normalizing the payload using change node&quot; alt=&quot;&amp;quot;Normalizing the payload using change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiment-anlaysis-change-node(1).png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;installing-custom-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#installing-custom-node&quot;&gt;Installing custom node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now it’s time to install a custom node that can perform sentiment analysis for us. In this guide, we will use the &lt;code&gt;node-red-node-sentiment&lt;/code&gt; which is a Node-RED node that uses the AFINN-165 wordlists for sentiment analysis of words. It returns a sentiment object containing a score and other properties but we will only use the score property. Score property typically ranges from -5 to 5.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;node-red-node-sentiment&lt;/code&gt; package by the Node-RED palette manager.&lt;/li&gt;
&lt;li&gt;Drag a sentiment node to canvas.&lt;/li&gt;
&lt;li&gt;Connect the change nodes output to sentiment node input.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;calculating-percentage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#calculating-percentage&quot;&gt;Calculating percentage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Why do we need to calculate the percentage? We will show the final result with the help of a circular progress bar and three different emojis. Ideally we should show the progress bar based on a percentage of score instead of negative values.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag another change node to canvas.&lt;/li&gt;
&lt;li&gt;set &lt;code&gt;msg.payload&lt;/code&gt; to &lt;code&gt;((msg.sentiment.score - (-5)) / (5 - (-5))) * 100&lt;/code&gt; as a JSONata expression, it will calculate the percentage of the score.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Calculating the percentage based on the score using the change node&quot; alt=&quot;&amp;quot;Calculating the percentage based on the score using the change node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiment-analysis-change-node(2).png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;displaying-result-on-dashboard-2.0&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#displaying-result-on-dashboard-2.0&quot;&gt;Displaying result on Dashboard 2.0&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, we are going to display the result on Dashboard 2.0 with the help of the Vuetify circular progress bar and emojis. To do that we will build a Vue component by using our ui template widget.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drag a ui template widget to canvas and create another group for it.&lt;/li&gt;
&lt;li&gt;Paste the below Vue component snippet into the template widget.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&#39;re aware that not everyone coming into Dashboard 2.0 will be familiar with VueJS. We have a more detailed guide &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#building-full-vue-components&quot;&gt;here&lt;/a&gt;, but we&#39;ll also give a quick overview of the component that we&#39;ll use to display the result:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-143&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-143&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-progress-circular&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:rotate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;360&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;245&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;15&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:model-value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg.payload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;rgb(0,255,0)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg.payload &amp;lt;= 33.33&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://i.ibb.co/VHKZ8sn/imgbin-smirk-emoji-face-emoticon-smile-png.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;sad emoji&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-else-if&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg.payload &amp;lt;= 66.66&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://i.ibb.co/nMnybLJ/imgbin-emoji-computer-icons-emoticon-smiley-png.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;neutral emoji&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-else&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://i.ibb.co/TK12RrH/Smile-Emoji-Face-PNG-Download-Image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;240&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;happy emoji&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-progress-circular&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-143&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;v-progress-circular is a Vuetify component to display a circular progress bar, for a detailed guide refer to our blog on  &lt;a href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/&quot;&gt;Custom Vuetify components for Dashboard 2.0&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rotate&lt;/code&gt; is an attribute that lets you specify the rotation angle of the progress bar.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; allow you to set the size of the circular progress bar, and another &lt;code&gt;width&lt;/code&gt; attribute allows you to set the stroke width of the circular progress bar.&lt;/li&gt;
&lt;li&gt;v-if, v-else-if, and v-else, allow dynamic rendering of elements based on specified conditions, in this component we are rendering emojis based on percentages calculated by score.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your final flow should look like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Node-RED flow to do sentiment analysis&quot; alt=&quot;&amp;quot;Node-RED flow to do sentiment analysis&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiment-anlaysis-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#deploying-the-flow&quot;&gt;Deploying the Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Deploying Sentiment analysis Node-RED flow&quot; alt=&quot;&amp;quot;Deploying Sentiment analysis Node-RED flow&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiement-analysis-flowfuse-editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Finally, we have successfully built our sentiment analysis system. Now it&#39;s time to deploy the flow, to do that click on the red deploy button which you can find in the top right corner. After that go to &lt;code&gt;https://&amp;lt;your-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Sentiment analysis on Text using Node-RED Dashboard 2.0&quot; alt=&quot;&amp;quot;Sentiment analysis on Text using Node-RED Dashboard 2.0&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sentiment-analysis-dashboard-gif.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/sentiment-analysis-with-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post, a sentiment analysis system is built with Node-RED in which the user has a form field to paste text content. After submitting the form, it calculates the percentage based on the output score, which ranges from -5 to 5. The output will be displayed on dashboard 2.0 by a circular progress bar and three different emojis based on percentage.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/</id>
        <title>Selecting a broker for your Unified Namespace</title>
        <summary>The broker is the data backbone for the unified namespace, which one is right for you?</summary>
        <updated>2024-01-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;When starting to roll out a new data distribution architecture for the unified namespace (UNS), one of the first questions you&#39;ll ask is, &amp;quot;What broker should I select for my UNS? The broker must implement a publish-subscribe (pub-sub) pattern, though that leaves plenty of options.&lt;/p&gt;
&lt;h2 id=&quot;technology-selection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#technology-selection&quot;&gt;Technology selection&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;two-protocols-frontrunners&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#two-protocols-frontrunners&quot;&gt;Two protocols frontrunners&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Currently, there are two protocols that are front runners for becoming the de facto data transfer choice in (industrial) IoT: &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka&lt;/a&gt;. They’ve been designed for different use cases and have different properties. At this time, MQTT is more often deployed as a broker in the unified namespace and is generally the best choice when starting to implement a unified namespace, it also features better support from hardware vendors.&lt;/p&gt;
&lt;p&gt;First and foremost, MQTT has been designed to enable IoT use cases. The main design objectives were to be lightweight to enable low-bandwidth communication, enable low-power devices, and handle unreliable networks. MQTT enables a large number of data producers and consumers to collaborate.&lt;/p&gt;
&lt;p&gt;Kafka is designed as an event streaming platform. Its initial adoption was mostly for data brokers between microservices all part of the same web backend for large sites like LinkedIn. When communicating data between servers or just a few data centers around the world, there’s less of a concern around the reliability of the connection or to enable constrained devices to participate in the shift towards a unified namespace.&lt;/p&gt;
&lt;p&gt;Generally, MQTT is more often seen deployed in practice as data distribution architecture.&lt;/p&gt;
&lt;h3 id=&quot;the-cloud-route&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#the-cloud-route&quot;&gt;The Cloud route&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cloud message queue brokers like AWS Kinesis and GCP Pub/Sub offer a high level of convenience. Scaling the infrastructure for real-time data processing and communication is their concern, the customer is mostly concerned about paying the bill. These brokers are fully managed, meaning they are maintained and updated by the cloud provider, reducing the burden on developers.&lt;/p&gt;
&lt;p&gt;However, this convenience comes with the tradeoff of vendor lock-in. When selecting these brokers, the cloud vendor has usually adapted their technology to support many protocols, and these offerings are usually jack-of-all-trades solutions – master of none. It creates a situation where the unified namespace implementation will change in subtle ways to accommodate the vendor instead of the other way around. An organization might become so reliant on a particular vendor&#39;s products or services that they are unable to easily switch to another vendor or protocol that serves their business objectives better. The cost of changing is exacerbated by having to train personnel on new and open-source protocols.&lt;/p&gt;
&lt;p&gt;In addition to vendor lock-in, cloud message queue brokers also introduce reliance on the network to the cloud providers. Network reliability for (industrial) IoT is a major concern due to the physically distributed nature, adding external dependencies creates more variability.&lt;/p&gt;
&lt;h3 id=&quot;exotic-options&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#exotic-options&quot;&gt;Exotic options&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;RabbitMQ is a widely used open-source message broker that’s mostly used as an event message bus for web applications. It can also function as a hub in a unified namespace. The broker primarily supports the &lt;a href=&quot;https://flowfuse.com/node-red/protocol/amqp/&quot;&gt;AMQP&lt;/a&gt; (Advanced Message Queuing Protocol), considered the industry standard for high-performance messaging systems. It also supports STOMP (Streaming Text Oriented Messaging Protocol) and MQTT (MQ Telemetry Transport), catering to various messaging needs.&lt;/p&gt;
&lt;p&gt;NATS, short for Network Agnostic Messaging System, is another open-source message broker that is designed for simplicity and reliability. NATS implements its own protocols, making it harder to be interoperable with hardware and software previously purchased. NATS has requirements on message structure too, which creates another barrier to adoption for IoT use cases.&lt;/p&gt;
&lt;h2 id=&quot;how-node-red-helps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#how-node-red-helps&quot;&gt;How Node-RED Helps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED provides a powerful and flexible way to integrate with various brokers, supporting protocols such as &lt;a href=&quot;https://flowfuse.com/blog/2024/06/how-to-use-mqtt-in-node-red/&quot;&gt;MQTT&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/blog/2024/03/using-kafka-with-node-red/&quot;&gt;Kafka&lt;/a&gt;, and &lt;a href=&quot;https://flowfuse.com/node-red/protocol/amqp/&quot;&gt;AMQP&lt;/a&gt;. It allows you to build and manage workflows that interact with your chosen broker, seamlessly connecting different data sources and systems.&lt;/p&gt;
&lt;p&gt;However, using Node-RED alone in production environments requires additional considerations, such as server deployment, instance management, security implementation, and scalability. This is where FlowFuse enhances Node-RED&#39;s capabilities by adding production-ready features. FlowFuse simplifies managing and deploying Node-RED applications, providing essential functionalities like scalability, robust security, and efficient collaboration tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and experience how FlowFuse can streamline your Node-RED deployments and management.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/unified-namespace-what-broker/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An MQTT broker is currently recommended as a broker solution for your unified namespace. There are many different implementations of the protocol available. At FlowFuse, we’re using &lt;a href=&quot;https://mosquitto.org/&quot;&gt;Mosquitto&lt;/a&gt;, due to its efficiency on resources and flexible authentication layer. Further, our customers are reporting to be happy with &lt;a href=&quot;https://www.emqx.io/&quot;&gt;EMqX&lt;/a&gt;, which is written in Erlang – itself a messaging-oriented programming language – and has been put through its paces in practice. If you’re dipping your toes into the unified namespace, either of those or another MQTT broker is currently recommended.&lt;/p&gt;
&lt;p&gt;Note that it’s recommended to allow yourself flexibility in the broker, and treat it as a message-passing system, and your organization will be able to easily swap it out later if any other broker is a better fit later on.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/</id>
        <title>FlowFuse 2.0 Release</title>
        <summary>Elevating Node-RED Device Management to new heights</summary>
        <updated>2024-01-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Following the release of FlowFuse 1.0 end of 2022, we&#39;re excited to release FlowFuse 2.0, marking a significant step in managing Node-RED remote instances, which we call Devices. FlowFuse already was the best place to operate Node-RED at scale in the cloud or on-premise, now it&#39;s able to manage Node-RED where ever it&#39;s run.&lt;/p&gt;
&lt;p&gt;Many organizations position Node-RED instances on remote servers like edge or industrial devices. This way they can meet network requirement, interact with analog protocols, and overcome other infrastructure requirements. Management of remote instances is crucial for the overall success of closing the gap between IT and OT. A key enhancement was the introduction of Device Groups (from version 1.15) and the new feature to assign target snapshots. This allows for direct and streamlined management of Node-RED Device fleets, setting the stage for future advancements in device management capabilities.&lt;/p&gt;
&lt;p&gt;For our FlowFuse users, this means it is no longer necessary or recommended to assign devices to an instance. Node-RED devices can be managed independently, and snapshots can be assigned via DevOps pipelines.&lt;/p&gt;
&lt;h2 id=&quot;enterprise-readiness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#enterprise-readiness&quot;&gt;Enterprise-Readiness&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is committed to augmenting the enterprise-readiness of Node-RED with introductions like &lt;a href=&quot;https://flowfuse.com/docs/admin/sso/&quot;&gt;Single Sign-On (SSO)&lt;/a&gt;, &lt;a href=&quot;https://flowfuse.com/docs/user/user-settings/#two-factor-authentication&quot;&gt;Multi-Factor Authentication (MFA)&lt;/a&gt;, and &lt;a href=&quot;https://flowfuse.com/docs/user/high-availability/&quot;&gt;High Availability&lt;/a&gt; since version 1.0. Furthermore, we recently achieved &lt;a href=&quot;https://flowfuse.com/blog/2024/01/soc2/&quot;&gt;SOC2 Type 1 compliance&lt;/a&gt;. With these advancements, Node-RED, in combination with FlowFuse, is genuinely ready for enterprise and production use.&lt;/p&gt;
&lt;h2 id=&quot;enhanced-integration-capabilities&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#enhanced-integration-capabilities&quot;&gt;Enhanced Integration Capabilities&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Node-RED Flow Library has always been a cornerstone, offering over 4800 connectors (nodes) for various OT and IT protocols. Thanks to the community and the Node-RED library. Building on this foundation, FlowFuse introduced &amp;quot;Certified Nodes&amp;quot; and &amp;quot;Blueprints&amp;quot;. These &lt;a href=&quot;https://flowfuse.com/blog/2023/10/blueprints/&quot;&gt;Blueprints&lt;/a&gt; are designed to provide an easier start with Node-RED, showcasing its full potential, while Certified Nodes ensure the security of the nodes used. Learn more about our new Certified Nodes &lt;a href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;developer-velocity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#developer-velocity&quot;&gt;Developer Velocity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED team development is made possible with FlowFuse. Different development team members are able to share and collaborate on the same Node-RED instance. This makes for much easier collaboration between Node-RED developers. We&#39;ve worked hard on maturing our &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/&quot;&gt;snapshot capabilties&lt;/a&gt; and introduced &lt;a href=&quot;https://flowfuse.com/docs/user/devops-pipelines/&quot;&gt;DevOps Pipelines&lt;/a&gt; that can be set up to stage Node-RED instances that have different development stages, e.g. test, development and production.&lt;/p&gt;
&lt;h2 id=&quot;looking-ahead&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#looking-ahead&quot;&gt;Looking Ahead&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At FlowFuse, our mission is to empower bottom-up innovation and enable organizations to transform their workflows into business-critical applications with unprecedented efficiency. As we move forward, we are excited to invite our users to actively engage with our future developments. Our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Roadmap&lt;/a&gt; lays out the advancements we&#39;re targeting, offering a glimpse into the features and enhancements that are on the horizon. We also encourage our users to stay informed and involved by checking out our latest updates in our detailed &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;changelog&lt;/a&gt;. Your insights and feedback are crucial to us; they fuel our commitment to continuous improvement and innovation. We warmly invite you to &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;share your thoughts and suggestions&lt;/a&gt;, as your input is a vital part of our journey in shaping the next steps for FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;how-to-get-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#how-to-get-started&quot;&gt;How to get started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running version 2.0.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The version 2.0 release of the FlowFuse Helm Chart includes a breaking change for deployments making use of the &lt;code&gt;forge.localPostgresql&lt;/code&gt; setting when upgrading. This is where the helm chart installs a dedicated PostgreSQL database instance.
With version 2.0 we have updated the version of the Bitnami PostgreSQL Helm sub-chart we bundle and the upgrade process will require some manual intervention to ensure things work correctly. A fresh install should not require any extra steps.&lt;/p&gt;
&lt;p&gt;The steps are documented on the &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/#upgrade&quot;&gt;Upgrade instructions&lt;/a&gt; page, please read them carefully before upgrading&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/flowfuse-release-2-0/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/</id>
        <title>Capture Data from edge devices with Node-RED</title>
        <summary>FlowFuse allows you to run Node-RED anywhere to capture all the data</summary>
        <updated>2024-01-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;While cloud computing has revolutionized data access and analysis, not all data can be accessed from the cloud. In many scenarios, data collection from the edge – the location where data is generated – is essential for real-time decision-making or process observability.&lt;/p&gt;
&lt;p&gt;FlowFuse enables data to be collected through Node-RED. Data can be processed locally on the edge or sent on to other services. FlowFuse doesn’t rely on continuous connections to the cloud, making it a good choice for locations with unreliable internet connectivity. Use cases like real-time monitoring of critical systems, proactive maintenance, and improved operational efficiency are now possible to implement.&lt;/p&gt;
&lt;h2 id=&quot;installing-the-flowfuse-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/#installing-the-flowfuse-agent&quot;&gt;Installing the FlowFuse agent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To manage the capturing of data on the edge we’re going to first install the FlowFuse agent. It’s installed on your device to manage the communication between the edge device and the FlowFuse server, manage the installation of Node-RED, its execution environment, and facilitate communication between devices and the cloud.&lt;/p&gt;
&lt;p&gt;The device agent can run anywhere you can run a Docker container or Node.JS runtime (version 16.0+) can be installed.&lt;/p&gt;
&lt;h3 id=&quot;registering-a-device-on-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/#registering-a-device-on-flowfuse&quot;&gt;Registering a device on FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For the edge device to know what it’s supposed to do, it needs to listen to the FlowFuse commands. The agent&#39;s configuration is provided by a &lt;code&gt;device.yml&lt;/code&gt; file from FlowFuse. Go to the team you’d like to add an edge device to, and select “Devices” on the left-hand menu, followed by the “Add Device” button.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Setting up a FlowFuse agent&quot; alt=&quot;Setting up a FlowFuse agent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowfuse-agent-setup.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse will prompt you to add a name (required), and a type (not required). When you’ve clicked &lt;code&gt;Add&lt;/code&gt; you’ll get a new dialog to download the required file.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The contents of a device.yml file&quot; alt=&quot;Configuration file for the FlowFuse agent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/device-yml-flowfuse.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;install-the-flowfuse-agent-through-docker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/#install-the-flowfuse-agent-through-docker&quot;&gt;Install the FlowFuse agent through Docker&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your device supports it, the fastest way to run the FlowFuse agent is with containers. Assuming you’ve already got Docker installed, there are two steps to follow: first, move the device YAML file downloaded from FlowFuse to the edge device and save it in &lt;code&gt;/opt/flowfuse/device.yml&lt;/code&gt;. Start the agent by running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --mount type=bind,src=/path/to/device.yml,target=/opt/flowfuse-device/device.yml -p 1880:1880 flowfuse/device-agent:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that for production cases, ensure the container is restarted on reboot. Docker can do this for you, &lt;a href=&quot;https://docs.docker.com/config/containers/start-containers-automatically/&quot;&gt;please follow their guide&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;install-the-flowfuse-agent-with-npm&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/#install-the-flowfuse-agent-with-npm&quot;&gt;Install the FlowFuse agent with npm&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To install the agent through NPM, you’ll need a Node.JS version of 18.0 or later. Open a command prompt and run: &lt;code&gt;npm install -g @flowfuse/device-agent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will install the FlowFuse Device Agent as a global npm module, making the flowfuse-device-agent command available in any directory on your system.&lt;/p&gt;
&lt;p&gt;Once the installation is complete, you must configure the Device Agent to connect to your FlowFuse instance. In this guide, you’ve previously downloaded the &lt;code&gt;device.yml&lt;/code&gt; file that’s needed now. On Linux or Mac, move the file to &lt;code&gt;/opt/flowfuse-device/device.yml&lt;/code&gt;, and for Windows-based systems, move the file to &lt;code&gt;c:&#92;opt&#92;flowfuse-device&#92;device.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Afterward, start the agent with: &lt;code&gt;flowfuse-device-agent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will launch the Device Agent and connect it to your FlowFuse instance. The Device Agent will wait for instructions on which flows to run.&lt;/p&gt;
&lt;h3 id=&quot;programming-flows-for-the-edge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/capture-data-edge-with-node-red-flowfuse/#programming-flows-for-the-edge&quot;&gt;Programming flows for the edge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now the agent is running, the FlowFuse platform will show it has contacted back to the platform and is ready to do some work. First, add it to the application and start the developer mode. That enables the device editor and provides you secure access to the editor anywhere in the world for everyone in the FlowFuse team with the right access role.&lt;/p&gt;
&lt;p&gt;When the development is done, be sure to create a snapshot of the developed flows to create a point-in-time backup, or to roll the snapshot out to many other devices later.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/soc2/</id>
        <title>FlowFuse is now SOC 2 Type 1 Compliant</title>
        <summary>FlowFuse&#39;s Path to SOC 2 Type 1 Compliance - A Testament to Our Commitment to Securing Customer and User Data.</summary>
        <updated>2024-01-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/soc2/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse achieved SOC 2 type 1 compliance! SOC 2, governed by the American Institute of Certified Public Accountants (AICPA), is a crucial framework for organizations handling customer data.
An independent audit assessed that FlowFuse&#39;s controls are effectively designed and operationally applied. Achieving SOC 2 Type 1 compliance validates our practises as an business and provides our customers assurances we apply the highest standards to ensure their data is protected.&lt;/p&gt;
&lt;h2 id=&quot;improving-our-security-posture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/soc2/#improving-our-security-posture&quot;&gt;Improving Our Security Posture&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At FlowFuse, we understand that professionalizing Node-RED deployments for our clients means adhering to the highest standards, including SOC 2 requirements. This commitment is at the core of our security philosophy. In a world rife with cybersecurity threats and data breaches, taking information security seriously isn&#39;t just an option—it&#39;s a critical necessity. Our SOC 2 audit was far more than just a procedural step. It represented a comprehensive, independent third-party validation of our robust controls and processes. We believe in transparency and accountability, which is why we document our policies in our open handbook, inviting scrutiny from vendors and reinforcing trust with our customers. Providing this level of independent audit not only serves our customers better and more efficiently but also offers FlowFuse valuable insights into enhancing our security measures and identifying any gaps in our policies. This proactive approach ensures we continue keeping your data safe and secure at all times.
As we continue to grow and evolve, ensuring the security of our systems and data becomes ever more critical. The next step on FlowFuse&#39;s journey to provide independant proof we&#39;re on the right track: We&#39;re currently in the observation phase of the SOC2 type 2.&lt;/p&gt;
&lt;p&gt;SOC 2 Type 1 assesses the design of an organization&#39;s security controls at a specific point in time, while SOC 2 Type 2 evaluates the effectiveness of those controls over a period of time, typically three to twelve months.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse&#39;s-journey-to-soc-2-compliance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/soc2/#flowfuse&#39;s-journey-to-soc-2-compliance&quot;&gt;FlowFuse&#39;s Journey to SOC 2 Compliance&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;compliance-partners&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/soc2/#compliance-partners&quot;&gt;Compliance Partners&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The independent audit was performed by Advantage Partners. Their expertise played a large role in our successful attainment of this certification. Before the audit was performed the company went through an extensive process to uncover what policies were missing, required updating, or were already in place. Further, lots of tribal knowledge has been written down and is now enforced by internal policies. For example&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/company/security/data-management/#data-management-policy&quot;&gt;Data Management Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/company/security/access-control/#access-control-policy&quot;&gt;Access Control Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/company/security/incident-response/#incident-response-plan&quot;&gt;Incident Response Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/handbook/company/security/human-resources/#human-resources-security-policy&quot;&gt;Human Resources Security Policy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&#39;s been a team effort from engineering to updated HR polices!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/send-a-file/</id>
        <title>Send a File to Node-RED</title>
        <summary>A guide to sending a CSV file to Node-RED and start interacting with it.</summary>
        <updated>2024-01-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/send-a-file/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Have you ever needed to send a CSV file to your Node-RED instance? This file can go on to populate a shift schedule, product specifications, or some other configuration file that is used. In this guide, we provide a couple of options to upload the data to your Node-RED for further processing and to organize the data to be sent on or used.&lt;/p&gt;
&lt;h2 id=&quot;why-would-you-need-to-send-a-file-to-node-red%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#why-would-you-need-to-send-a-file-to-node-red%3F&quot;&gt;Why would you need to send a file to Node-RED?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Often times it is necessary to update lookup tables in a SQL database, but you don&#39;t necessarily want to give access to everyone to edit the database, nor do you want to have to do it all yourself. This can often be seen when new products are introduced into a manufacturing facility. It may not be often, but enough that it warrants its own application. This process will guide you in a way that will enable your teammates to upload the files to the system themselves.&lt;/p&gt;
&lt;p&gt;Furthermore, on the management layer of most companies, Excel and Google Sheets are the go-to tools to perform data collection tasks. Getting management involved in processes might require you to build an import feature for them. Asking your manager to &amp;quot;Save as&amp;quot; CSV is much easier than teaching them SQL!&lt;/p&gt;
&lt;h2 id=&quot;2-ways-to-send-a-file-to-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#2-ways-to-send-a-file-to-node-red&quot;&gt;2 Ways to send a file to Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many approaches that can be taken when solving this. We are going to go over 2 here.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#simple-python-script&quot;&gt;Simple Python Script&lt;/a&gt; - Simple script that will be shared below. It is a simple Python application that allows the user to send a file with a simple command, but this might require a little more technical skills that the end user may not feel comfortable with.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#stand-alone-web-application&quot;&gt;Stand Alone Web Application&lt;/a&gt; - A web-based application that allows the user to upload files to a browser with a selectable endpoint.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;simple-python-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#simple-python-script&quot;&gt;Simple Python Script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This simple Python script sends a file to a Node-RED flow.  The flow that will work with this script can be seen &lt;a href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#node-red-ingress&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The script requires &lt;strong&gt;requests&lt;/strong&gt; and &lt;strong&gt;Python 3.x&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Install requests:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-42&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-42&quot; class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; requests&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-42&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Create a file called run.py and paste the contents into the file.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-46&quot;&gt;
  &lt;pre class=&quot;language-python&quot;&gt;&lt;code id=&quot;code-46&quot; class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; requests&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;send_file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nodered_url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Open the file in binary mode&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file_path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;rb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;        files &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;file&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;multipart/form-data&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nodered_url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; files&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Update the ip address and port of your Node-RED instance&lt;/span&gt;&lt;br /&gt;nodered_url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;http://localhost:1880/fileupload&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Update the location of your file&lt;/span&gt;&lt;br /&gt;file_path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;C:/Users/myUser/Downloads/shiftSchedule.csv&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; send_file&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nodered_url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Response Status Code: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status_code&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Response Body: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-46&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Update the &lt;strong&gt;nodered_url&lt;/strong&gt; to the location of the Node-RED instance.  Be sure to adjust the port if the default port of 1880 isn&#39;t being used.&lt;/p&gt;
&lt;p&gt;Update the &lt;strong&gt;file_path&lt;/strong&gt; with the path to where the file to be uploaded will be located.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To run:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-59&quot;&gt;
  &lt;pre class=&quot;language-python&quot;&gt;&lt;code id=&quot;code-59&quot; class=&quot;language-python&quot;&gt;python run&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;py&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-59&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;stand-alone-web-application&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#stand-alone-web-application&quot;&gt;Stand Alone Web Application&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;csv upload application&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/csv_upload_app.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This stand-alone web application can be run on either Windows or Linux, .bat for Windows, and .sh for Linux.&lt;/p&gt;
&lt;h4 id=&quot;installation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#installation&quot;&gt;Installation&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Clone the repository and navigate to the directory:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-75&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-75&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/gdziuba/FF_Send-File-to-NR.git &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; FF_Send-File-to-NR&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-75&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#configuration&quot;&gt;Configuration&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Edit the lines in the body of &lt;a href=&quot;https://github.com/gdziuba/FF_Send-File-to-NR/blob/21214f88c6c4536f49efb88cf5f84bf52071a88b/templates/index.html#L69&quot;&gt;index.html&lt;/a&gt; to include the endpoints to which you would like to send the files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;option value=&amp;quot;http://localhost:1880/fileupload&amp;quot;&amp;gt;CSV File Upload&amp;lt;/option&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;operating-systems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#operating-systems&quot;&gt;Operating Systems&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;windows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#windows&quot;&gt;Windows&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Run the script:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-92&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-92&quot; class=&quot;language-bash&quot;&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;start_app.bat&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-92&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will install if necessary, start the Flask Application, and take you to localhost:5000 on the browser.&lt;/p&gt;
&lt;h4 id=&quot;linux&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#linux&quot;&gt;Linux&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Make the script executable by running running:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-102&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-102&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x setup_and_run.sh&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-102&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Then run the application with:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-106&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-106&quot; class=&quot;language-bash&quot;&gt;./setup_and_run.sh&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-106&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;To access the application, open a browser to the &lt;strong&gt;&amp;lt;node-red-host-ip&amp;gt;:5000&lt;/strong&gt; of the running application.&lt;/p&gt;
&lt;h4 id=&quot;node-red-ingress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#node-red-ingress&quot;&gt;Node-RED Ingress&lt;/a&gt;&lt;/h4&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;225px&quot; src=&quot;https://flows.nodered.org/flow/effb53752e5d6f767b3c7e5d41a4a6e8/share?height=100&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Once we have a file ready to be sent, we now need to configure the receiving side in Node-RED. In this example, we are leveraging a CSV formatted file and then converting it to be used at a later time.&lt;/p&gt;
&lt;p&gt;A link to the flow can be found &lt;a href=&quot;https://flows.nodered.org/flow/effb53752e5d6f767b3c7e5d41a4a6e8&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To import the flow, follow these &lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#1.-copy-and-share-your-flows-using-export-and-import&quot;&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A Simple HTTP In node can be used in the form of a Post, ensuring the configuration allows for a file.&lt;/p&gt;
&lt;h2 id=&quot;wanna-import-it-directly-into-your-node-red-instance-via-a-dashboard%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/#wanna-import-it-directly-into-your-node-red-instance-via-a-dashboard%3F&quot;&gt;Wanna import it directly into your Node-RED instance via a Dashboard?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Check out this &lt;a href=&quot;https://flowfuse.com/blog/2024/01/import-a-file/&quot;&gt;blog&lt;/a&gt; on how to directly import a file into a Node-RED instance via Dashboard 2.0.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2024/01/import-a-file/</id>
        <title>Import a File into Node-RED with Dashboard 2.0</title>
        <summary>Use Dashboard 2.0 to import a CSV file into Node-RED.</summary>
        <updated>2024-01-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2024/01/import-a-file/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Need to get a file into Node-RED, but don&#39;t want to over complicate things.  This article outlines how you can leverage Dashboard 2.0 to import a file directly into Node-RED via a Dashboard.&lt;/p&gt;
&lt;h2 id=&quot;why-would-you-need-to-import-a-file-to-node-red%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/import-a-file/#why-would-you-need-to-import-a-file-to-node-red%3F&quot;&gt;Why would you need to import a file to Node-RED?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Often times it is necessary to update lookup tables in a SQL database, but you don&#39;t necessarily want to give access to everyone to edit the database, nor do you want to have to do it all yourself. This can often be seen when new products are introduced into a manufacturing facility. It may not be often, but enough that it warrants its own application. This process will guide you in a way that will enable your teammates to upload the files to the system themselves.&lt;/p&gt;
&lt;p&gt;Furthermore, on the management layer of most companies, Excel and Google Sheets are the go-to tools to perform data collection tasks. Getting management involved in processes might require you to build an import feature for them. Asking your manager to &amp;quot;Save as&amp;quot; CSV is much easier than teaching them SQL!&lt;/p&gt;
&lt;h3 id=&quot;node-red-dashboard-(flowfuse)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/import-a-file/#node-red-dashboard-(flowfuse)&quot;&gt;Node-RED Dashboard (FlowFuse)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;csv dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/csv-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This simple flow allows the user to visualize data from a CSV in the Node-RED Dashboard. The button then allows the user to initiate a request to send the data to the next step. This next step could be anything from loading into a SQL database to saving it.&lt;/p&gt;
&lt;h3 id=&quot;instructions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/import-a-file/#instructions&quot;&gt;Instructions&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install Node-RED Dashboard 2.0. Follow these &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;instructions&lt;/a&gt; to install.&lt;/li&gt;
&lt;li&gt;Import Flow - to import the flow into your Node-RED instance follow these &lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#1.-copy-and-share-your-flows-using-export-and-import&quot;&gt;instructions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Access Dashboard - To access the dashboard, navigate to the &lt;code&gt;https://&amp;lt;flowfuse-instance-name&amp;gt;.flowfuse.cloud/dashboard&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This dashboard is currently configured to take in CSV files and transform them into a single message that is sent to the table for visualization.  Simultaneously the data from the import is stored locally in the flow context.  From there, the button can be used to trigger the sending of the data from the flow context to the next destination.  In this case, it is a simple debug node.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;225px&quot; src=&quot;https://flows.nodered.org/flow/8c505039ac1b8dbed2bee1e22ee2975a/share?height=100&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;need-to-send-a-file-to-node-red-from-another-application-or-source%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2024/01/import-a-file/#need-to-send-a-file-to-node-red-from-another-application-or-source%3F&quot;&gt;Need to Send a File to Node-RED from another application or source?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Check out this &lt;a href=&quot;https://flowfuse.com/blog/2024/01/send-a-file/&quot;&gt;blog&lt;/a&gt; on how to send a file from either a stand alone web application or use the sample python script to imbed it into your current application.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/</id>
        <title>Data Modeling for your Unified Namespace</title>
        <summary>How to use FlowFuse as your Schema Registry?</summary>
        <updated>2023-12-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;In the realm of industrial manufacturing, the concept of a Unified Namespace (UNS) emerges as a pivotal instrument for enhanced communication within a manufacturing network framework. Predicated on an event-driven architectural model, this approach advocates for the universal accessibility of data, irrespective of the immediate presence of a data consumer.
This paradigm allows for a flexible role allocation within the network, where nodes can dynamically switch between being data producers and consumers, contingent upon the fluctuating requirements of the system at any specific juncture. For those unfamiliar with UNS, I recommend revisiting my &lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/&quot;&gt;previous article&lt;/a&gt; on the subject.&lt;/p&gt;
&lt;p&gt;This article aims to explain the process of data modeling for your UNS, highlighting the role of tools like the FlowFuse Team Library in schema management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overview of Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-1---connection-to-your-operational-technology-(ot)-equipment&quot;&gt;Connection to your Operational Technology (OT) equipment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-2---structuring-your-payload&quot;&gt;Structuring your payload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-3---building-your-topic-hierarchy&quot;&gt;Building your Topic Hierarchy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-4---connection-to-your-unified-namespace&quot;&gt;Connection to your Unified Namespace&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-1---connection-to-your-operational-technology-(ot)-equipment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-1---connection-to-your-operational-technology-(ot)-equipment&quot;&gt;Step 1 - Connection to your Operational Technology (OT) equipment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The journey begins with establishing connections to OT equipment, which may include Programmable Logic Controllers (PLCs), Historian databases, and sensors. It is essential to facilitate compatibility with a diverse array of protocols. In this context, Node-RED emerges as a pivotal tool, bolstered by its expansive community-generated catalog featuring over 4500 nodes.&lt;/p&gt;
&lt;p&gt;In my example, the focus is on integration with a RevolutionPi. To achieve this, the FlowFuse Device Agent was deployed on a RevolutionPi (see our &lt;a href=&quot;https://flowfuse.com/docs/hardware/raspbian/&quot;&gt;documentation&lt;/a&gt;), and specific RevolutionPi nodes were installed. These nodes enable direct interaction with all interfaces of the PLC and are available through the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-revpi-nodes&quot;&gt;Node-RED library&lt;/a&gt;. Subsequent steps involved acquiring temperature data directly from the PLC.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/revpi_nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For optimal data accuracy and integrity, it is recommended to timestamp data at the point of origin. In our scenario, the PLC outputs lack inherent timestamping. Consequently, I integrated a timestamp at the data acquisition stage within Node-RED, which runs on the same hardware.&lt;/p&gt;
&lt;p&gt;A general recommendation is the imperative of maintaining data integrity during transmission from OT systems to the message broker. This is particularly salient in regulated sectors such as pharmaceuticals, where standards like GxP mandate the preservation of unaltered data during transfer to the UNS.&lt;/p&gt;
&lt;h2 id=&quot;step-2---structuring-your-payload&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-2---structuring-your-payload&quot;&gt;Step 2 - Structuring your payload&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The payload is the core of transmitted data. Transforming the payload for mutual intelligibility between sender and receiver, even within the same protocol, is sometimes necessary. Standardizing payload formats ensures consistent data storage and transmission. I recommend including schema type information with the data to cater to diverse use cases.&lt;/p&gt;
&lt;p&gt;Utilizing FlowFuse and Node-RED can enforce schema consistency. Node-RED&#39;s template node lets you define JSON schemas for your flows, while the FlowFuse Team Library facilitates schema sharing and consistency across your organization.&lt;/p&gt;
&lt;p&gt;In my example, I use a very simple JSON schema as a structure for measurements for &lt;code&gt;StationA&lt;/code&gt;:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-61&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-61&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;$schema&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Enterprise/Site/Line1/StationA/measurements/_schema&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Measurement Schema for StationA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The actual value being measured&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The unit of the measurement value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The timestamp of the measurement in ISO 8601 format&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-61&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Example Data:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-65&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-65&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg.payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Celsius&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg.timestamp&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-65&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Node-RED template node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/template_node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The FlowFuse Team Library acts as my schema registry within my organization, allowing me to reuse my schemas and ensure consistency.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;FlowFuse Team Library&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/team_library.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-3---building-your-topic-hierarchy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-3---building-your-topic-hierarchy&quot;&gt;Step 3 - Building your Topic Hierarchy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Your topic hierarchy should reflect your physical plant structure or align with existing asset naming systems. This approach improves data visibility and eases navigation for OT engineers. Many enterprises opt for the &lt;a href=&quot;https://www.isa.org/products/ansi-isa-95-00-02-2018-enterprise-control-system-i&quot;&gt;ISA-95 part 2&lt;/a&gt; model to structure their topics.&lt;/p&gt;
&lt;p&gt;In our example, we follow the structure of: Enterprise/Site/Line1/StationA&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;MQTT Topic Tree&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mqtt_topic_tree.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-4---connection-to-your-unified-namespace&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#step-4---connection-to-your-unified-namespace&quot;&gt;Step 4 - Connection to your Unified Namespace&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, transfer your data to the UNS, using protocols like MQTT or Kafka, depending on your UNS setup. While MQTT can handle up to 256 MB per payload, Kafka&#39;s default is 1MB, expandable to 10MB. These capacities suffice for most data types. In our example, we&#39;ll employ MQTT.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, implementing a Unified Namespace (UNS) with efficient data modeling is a transformative step for any industrial manufacturing setup. By leveraging tools like FlowFuse Team Library, Node-RED, and protocols such as MQTT or Kafka, organizations can achieve a harmonious data ecosystem where information flows seamlessly across various nodes. As illustrated through practical examples, including the integration with a RevolutionPi, the importance of standardizing data schemas, maintaining data integrity, and structuring topic hierarchies cannot be overstated. Embracing these practices not only enhances operational efficiency but also paves the way for more advanced analytics and machine learning applications.&lt;/p&gt;
&lt;h3 id=&quot;the-complete-node-red-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/unified-namespace-data-modelling/#the-complete-node-red-flow&quot;&gt;The complete Node-RED flow&lt;/a&gt;&lt;/h3&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;225px&quot; src=&quot;https://flows.nodered.org/flow/f6c783c6e9c1863145e0c63418eb5fe5/share?height=100&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/</id>
        <title>Thank you for an incredible 2023!</title>
        <summary>Reviewing an amazing 2023 for FlowFuse</summary>
        <updated>2023-12-22T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;At the end of the year there’s always an opportunity to review how the year went, and I&#39;m gonna take this opportunity to share the review of 2023 for FlowFuse. It&#39;s been an incredible year for FlowFuse and we&#39;ve achieved a lot with our team.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-branding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/#flowfuse-branding&quot;&gt;FlowFuse branding&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First off; in 2023 we were known as FlowForge. But, due to some trademark challenges, we went through a &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/&quot;&gt;rebranding phase&lt;/a&gt; over the summer. It&#39;s been a bit of an adjustment, and you might still catch us – and even some of our customers – occasionally slipping up with the old name. But overall, we&#39;re really pleased with how smoothly everything&#39;s transitioned.&lt;/p&gt;
&lt;h3 id=&quot;product-adoption&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/#product-adoption&quot;&gt;Product adoption&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the product side: Growth in adoption of the FlowFuse platform has been tremendous, in many dimensions; revenue generated, customers onboarded, and how many users are now professionalizing their usage of Node-RED. Our development platform has been used by thousands of developers to acquire data from various sources and visualize it to build rich applications for their use cases. And at every step of the way we’ve been able to improve their experience.&lt;/p&gt;
&lt;p&gt;Data acquisition was always possible  without FlowFuse, however we’ve improved on the status quo through the &lt;a href=&quot;https://flowfuse.com/certified-nodes/&quot;&gt;Certified Nodes&lt;/a&gt; program. A nascent program that vets often used custom nodes from the community to ensure business readiness and validate nodes to ensure there’s no malicious code installed.&lt;/p&gt;
&lt;p&gt;Further, this year we’ve started &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Dashboard 2.0&lt;/a&gt;. The development of the successor of &lt;a href=&quot;https://flows.nodered.org/node/node-red-dashboard&quot;&gt;node-red-dashboard&lt;/a&gt;, which is built on deprecated technology and effectively on life-support. The development of the new Dashboard technology has taken massive steps and it’s very stable. Feature parity is not yet achieved, though we’re happy with the adoption of Dashboard 2.0 and the community &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues&quot;&gt;reporting issues and improvements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the product improvements to FlowFuse, we’ve empowered large audiences to try and adopt the product. We’ve seen adoption in many areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Process manufacturing – Mining, oil &amp;amp; gas, beverages.&lt;/li&gt;
&lt;li&gt;Discrete manufacturing – Ranging from automotive to logistics use-cases.&lt;/li&gt;
&lt;li&gt;Digital transformation – Digital only integration, from website back-ends to workflow engines for up-skilled employees.&lt;/li&gt;
&lt;li&gt;Agriculture – From environment monitoring to controlling sprinklers, water-pumps, and more.&lt;/li&gt;
&lt;li&gt;Education &amp;amp; Research – Hundreds of students have registered for FlowFuse to learn how IIoT works, start building solutions, and prepare themselves for employing these skills in their first jobs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’re always happy to &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;support you&lt;/a&gt; in any of these or other industries where you may find value in how we streamline operations, manage your data acquisition logic and roll out, and remain compliant during your journey.&lt;/p&gt;
&lt;h3 id=&quot;pricing-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/#pricing-changes&quot;&gt;Pricing changes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A driving force behind the horizontal nature of adoption of the FlowFuse development platform has been the introduction of the 3 product tiers earlier this year. We’ve introduced a Starter package, Team and Enterprise tiers.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/&quot;&gt;starter package&lt;/a&gt; allows everyone to adopt the core features of FlowFuse and Node-RED. It provides hosting of 2 Node-RED instances in the Cloud and management of 2 Node-REDs on the edge.&lt;/p&gt;
&lt;p&gt;A user can be promoted to the &lt;a href=&quot;https://flowfuse.com/changelog/2023/09/introduction-enterprise-tier/&quot;&gt;Team or Enterprise tier&lt;/a&gt; when they’re ready to further professionalize their adoption and have access to enhanced compliance, faster time to value for their developers, among other features.&lt;/p&gt;
&lt;h3 id=&quot;what-2024-will-bring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/#what-2024-will-bring&quot;&gt;What 2024 will bring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse will continue to support the Node-RED community at large. In 2024 we’re looking to further grow into the main development platform for low-code developers. While our main focus will remain around Node-RED, there’s more to be done to become the defacto low-code development platform. Core of which are a few pillars:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Time to value for developers&lt;/li&gt;
&lt;li&gt;Empowering more employees to automate the software layer of the solution&lt;/li&gt;
&lt;li&gt;Enhanced compliance and enforcement&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’re hoping to continue to serve our customers and grow the customer base in 2024!&lt;/p&gt;
&lt;h3 id=&quot;holiday-season-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/flowfuse-year-review-2023/#holiday-season-support&quot;&gt;Holiday Season Support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Over the next couple of weeks (22nd December - 2nd January), most of our team will be taking some well deserved time off. Don&#39;t worry, we will still be available if you need emergency support. The best way to contact us is via our website&#39;s &lt;a href=&quot;https://flowfuse.com/support/&quot;&gt;support page&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/</id>
        <title>Introduction to the Unified Namespace (UNS) – 2026 Updated Guide</title>
        <summary>Making data available for Industry 4.0 use-cases</summary>
        <updated>2023-12-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;As your organization is generating more data there’s key architectural
decisions to be made to ensure the full value can be unlocked and you’re
leveraging not just the tip of the iceberg. The &lt;a href=&quot;https://flowfuse.com/solutions/uns/&quot;&gt;Unified Namespace (UNS)&lt;/a&gt;
provides a blueprint to allow data to be consumed by many data-consumers.
FlowFuse helps you manage this migration and the operationalization of your
data.&lt;/p&gt;
&lt;p&gt;To facilitate a many to many connection between data producers and data consumers, there are two changes to be made to your architecture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Data transport through a hub-and-spokes model&lt;/li&gt;
&lt;li&gt;Set structure of the Data&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;hub-and-spokes-model-replaces-point-to-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/#hub-and-spokes-model-replaces-point-to-point&quot;&gt;Hub and spokes model replaces Point to Point&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Traditionally, for example web servers serving web pages, the client requests a
page from a server. This is a point to point connection between those two parties.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Point to Point connection&quot; alt=&quot;Point to point graphic&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/uns-point-to-point.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For the same data to be transmitted to a new data consumer, the consumer needs
to make another request to obtain the data. This works great when you know what
data you need for building your solution, and if you know where to get it.&lt;/p&gt;
&lt;p&gt;However, in manufacturing it’s not always possible to know up front who will
need your data. Some machines are built and placed years before another machine
would like to interact with the generated data. There might be many consumers
for the same data set. Lastly; consumers might not know when to fetch new data
points, and thus will try on a cycle or need another mechanism to understand if
new data is available. Also, there are many challenges in point-to-point connections.
For a deeper explanation, read &lt;a href=&quot;https://flowfuse.com/blog/2024/11/why-point-to-point-connection-is-dead/&quot;&gt;Why point-to-point connection is dead&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is why a hub and spoke model should be employed. For each data source or
data producer, a connection is made to a central hub; generally called a broker.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Unified Namespace Hub and Spokes communication&quot; alt=&quot;Hub and spoke graphic&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/uns-hub.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;structured-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/#structured-data&quot;&gt;Structured data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When many producers are connected to many data consumers, but not directly,
the data producer needs to provide insight into what the events can be and will
contain. It cannot, nor should even if it could, tailor the event’s data structure
for a consumer so there’s decoupling on an architecture level. Structured data
makes information, without structure the consumer receives mere bytes.&lt;/p&gt;
&lt;p&gt;This means that a schema for each event should be created and maintained. A
schema which both the producer and consumer can read and validate each event
against. As such a common Schema Definition Language (SDL) is chosen to provide
clarity of how the data is structured, how it can be parsed, and in some cases
also what it means for the developer.&lt;/p&gt;
&lt;h2 id=&quot;how-node-red-fits-in&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/#how-node-red-fits-in&quot;&gt;How Node-RED Fits In&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED excels in implementing a Unified Namespace with its flexible and powerful capabilities. It can act as both a central hub and a data consumer within a hub-and-spokes model, simplifying the integration of various data sources and consumers. By leveraging Node-RED&#39;s extensive library of nodes and its easy-to-use flow-based programming interface, organizations can efficiently manage data ingestion, transformation, and distribution.&lt;/p&gt;
&lt;p&gt;Node-RED also supports structured data through its support for JSON, XML, and other standard formats, allowing for clear and consistent data schemas. With its built-in nodes for MQTT, HTTP, and other protocols, Node-RED can seamlessly integrate with existing systems, enabling real-time data exchange and visualization. This makes it an ideal tool for operationalizing the Unified Namespace, ensuring that data flows efficiently and is readily available to all relevant stakeholders.&lt;/p&gt;
&lt;p&gt;Read this article to learn how you can build your Unified Namespace using Node-RED and FlowFuse: &lt;a href=&quot;https://flowfuse.com/blog/2024/11/building-uns-with-flowfuse/&quot;&gt;Building a Unified Namespace with FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also watch this webinar that explores the core concepts of the Unified Namespace, explains why it is essential for Industry 4.0, and demonstrates how FlowFuse and HiveMQ can be used together to build a scalable Unified Namespace.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;z62O5RrOK8o&quot; params=&quot;rel=0&quot; style=&quot;margin-top: 20px; margin-bottom: 20px; width: 100%; height: 480px;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-flowfuse-can-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/introduction-to-unified-namespace/#how-flowfuse-can-help&quot;&gt;How FlowFuse Can Help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While Node-RED is highly effective for implementing UNS, managing and deploying it can be complex. FlowFuse provides a unified platform that simplifies deployment with one-click operations, secure management, and scalable Node-RED applications. It also includes features that enhance collaboration, alongside offering centralized management of all Node-RED instances to ensure streamlined operations and increased efficiency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and experience FlowFuse&#39;s features&lt;/strong&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/</id>
        <title>Run Node-RED as a service on Windows</title>
        <summary>Step by step guide to run FlowFuse device agent as a Windows service</summary>
        <updated>2023-12-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/"/>
        <author><name>Steve McLaughlin</name></author>
        <author><name>Rob Marcer</name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse&#39;s device agent allows you to manage and run your Node-RED instances on
your own hardware such as a Raspberry Pi or Windows computer. This can be very useful where an
application you&#39;ve written needs to run flows with direct access to hardware sensors.&lt;/p&gt;
&lt;p&gt;In this article, we&#39;re going to explain the steps to configure our device agent to run as a service in Windows
using the &lt;a href=&quot;https://nssm.cc/&quot;&gt;nssm&lt;/a&gt; utility.&lt;/p&gt;
&lt;h2 id=&quot;why-run-the-device-agent-as-a-service%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#why-run-the-device-agent-as-a-service%3F&quot;&gt;Why run the device agent as a service?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The standard process for running FlowFuse&#39;s device agent is to start it on the
command line using the command &lt;code&gt;flowfuse-device-agent&lt;/code&gt;. This works fine for testing
but for long-term installations it&#39;s useful to run the device agent as a service.
Once running as a service, the device agent will continue to run even if you
log off or the computer is restarted and no user is logged in.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The aim of this how-to is to install the FlowFuse device-agent as a service on a Windows computer.&lt;/p&gt;
&lt;p&gt;There will be two main parts to this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the device-agent&lt;/li&gt;
&lt;li&gt;Setup the device-agent to run as a Windows service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additionally, two user accounts will be needed for this configuration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;user&lt;/strong&gt; account that will be used to run the device-agent (typically, non-admin account)&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;admin&lt;/strong&gt; account that can run elevated commands and will be used to setup the service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will create a directory for the device-agent files and set the permissions on that directory so that the &lt;strong&gt;user&lt;/strong&gt; account can read and write files in that directory.
&lt;em&gt;This will be &lt;code&gt;c:&#92;opt&#92;flowfuse-device&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To make the device-agent run as a service, we will (in this example), use &lt;a href=&quot;https://nssm.cc/&quot;&gt;nssm&lt;/a&gt; but you are free to choose an alternative tool to run the device agent as a service.&lt;/p&gt;
&lt;p&gt;Finally, we set the service to run under the &lt;strong&gt;service&lt;/strong&gt; account.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE: The instructions in this how to were written on &lt;strong&gt;Windows 11 Pro 22H2&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;tip%3A-using-domain-accounts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-using-domain-accounts&quot;&gt;TIP: Using domain accounts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the account is a domain account, append the domain name to the &lt;strong&gt;user&lt;/strong&gt; e.g. &lt;code&gt;user@domain&lt;/code&gt; whenever the &lt;strong&gt;user&lt;/strong&gt; name is used in the instructions below.&lt;/p&gt;
&lt;h3 id=&quot;tip%3A-launching-an-elevated-command-prompt-window-(e.g.-as-the-admin-user)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-command-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;TIP: Launching an elevated command prompt window (e.g. as the admin user)&lt;/a&gt;&lt;/h3&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-69&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-69&quot; class=&quot;language-bash&quot;&gt;powershell &lt;span class=&quot;token parameter variable&quot;&gt;-Command&lt;/span&gt; &quot;Start-Process &lt;span class=&quot;token string&quot;&gt;&#39;cmd&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-Verb&lt;/span&gt; runAs&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-69&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;tip%3A-launching-an-elevated-powershell-prompt-window-(e.g.-as-the-admin-user)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-powershell-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;TIP: Launching an elevated powershell prompt window (e.g. as the admin user)&lt;/a&gt;&lt;/h3&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-73&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-73&quot; class=&quot;language-bash&quot;&gt;powershell &lt;span class=&quot;token parameter variable&quot;&gt;-Command&lt;/span&gt; &quot;Start-Process &lt;span class=&quot;token string&quot;&gt;&#39;powershell&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-Verb&lt;/span&gt; runAs&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-73&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;pre-requisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#pre-requisites&quot;&gt;Pre-requisites&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;install-node.js&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#install-node.js&quot;&gt;Install Node.js&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The device-agent requires Node.js to be installed. You can download the latest version from https://nodejs.org/en/download/.&lt;/p&gt;
&lt;p&gt;It is recommended to install the LTS version and to check the &amp;quot;Automatically install the necessary tools&amp;quot; option. This is especially important if you intend on using any nodes that require native modules (like serialport).&lt;/p&gt;
&lt;h3 id=&quot;create-a-new-windows-user&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#create-a-new-windows-user&quot;&gt;Create a New Windows User&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you need to create a new &lt;strong&gt;user&lt;/strong&gt; account follow these &lt;a href=&quot;https://support.microsoft.com/en-us/windows/create-a-local-user-or-administrator-account-in-windows-20de74e0-ac7f-3502-a866-32915af2a34d#:~:text=Select%20Start%20%3E%20Settings%20%3E%20Accounts%20and,other%20user%2C%20select%20Add%20account.&quot;&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;prepare-the-device-agent-files-directory&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#prepare-the-device-agent-files-directory&quot;&gt;Prepare the device-agent files directory&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the admin user, open an &lt;a href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-command-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;elevated&lt;/a&gt; command prompt, create the files directory and setup access permissions.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-98&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-98&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# In an elevated command prompt&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;flowfuse-device&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# grant full access to the service account that will run the device-agent&lt;/span&gt;&lt;br /&gt;icacls c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;flowfuse-device /grant &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;:F /T&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-98&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;where &lt;code&gt;&amp;quot;user&amp;quot;&lt;/code&gt; is the service account (not the admin account)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;install-nssm&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#install-nssm&quot;&gt;Install nssm&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nssm&lt;/code&gt; can simply be downloaded and executed from any path.
We will download it to the &lt;code&gt;c:&#92;opt&lt;/code&gt; directory, extract the files and copy the 64 bit version to the current directory.&lt;/p&gt;
&lt;h3 id=&quot;cmd-version-elevated-command-prompt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#cmd-version-elevated-command-prompt&quot;&gt;&lt;code&gt;cmd&lt;/code&gt; version &lt;a href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-command-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;elevated&lt;/a&gt; command prompt&lt;/a&gt;&lt;/h3&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-111&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-111&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# starting in the device-agent files directory&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# download the nssm zip file&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-LJO&lt;/span&gt; https://nssm.cc/release/nssm-2.24.zip&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# extract the files&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-xf&lt;/span&gt; nssm-2.24.zip&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# copy the 64 bit version to the current directory&lt;/span&gt;&lt;br /&gt;copy nssm-2.24&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;win64&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;nssm.exe &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# clean up&lt;/span&gt;&lt;br /&gt;del nssm-2.24.zip&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;rmdir&lt;/span&gt; /s /q nssm-2.24&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-111&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;powershell-version-elevated-powershell-prompt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#powershell-version-elevated-powershell-prompt&quot;&gt;&lt;code&gt;powershell&lt;/code&gt; version &lt;a href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-powershell-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;elevated&lt;/a&gt; powershell prompt&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you don&#39;t have &lt;code&gt;cURL&lt;/code&gt; installed, then powershell can be used to download the file. Here is how to do it:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-118&quot;&gt;
  &lt;pre class=&quot;language-powershell&quot;&gt;&lt;code id=&quot;code-118&quot; class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# starting in the device-agent files directory&lt;/span&gt;&lt;br /&gt;cd c:&#92;opt&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# download the nssm zip file&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Uri https:&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;nssm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cc/release/nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zip &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;OutFile nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zip&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# extract the files&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Expand-Archive&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zip &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# copy the 64 bit version to the current directory&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Copy-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&#92;nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24&#92;win64&#92;nssm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exe &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Destination &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# clean up&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Remove-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zip&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Remove-Item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path nssm-2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;24 &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Recurse&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-118&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;manual-download&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#manual-download&quot;&gt;Manual download&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you prefer, you can download the nssm zip file manually from &lt;a href=&quot;https://nssm.cc/release/nssm-2.24.zip&quot;&gt;https://nssm.cc/release/nssm-2.24.zip&lt;/a&gt; and extract the files to the &lt;code&gt;c:&#92;opt&lt;/code&gt; directory. Then copy the 64 bit version to the current directory.&lt;/p&gt;
&lt;p&gt;Ultimately, you should end up with a file named &lt;code&gt;nssm.exe&lt;/code&gt; in the &lt;code&gt;c:&#92;opt&#92;&lt;/code&gt; directory.&lt;/p&gt;
&lt;h2 id=&quot;install-and-configure-the-device-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#install-and-configure-the-device-agent&quot;&gt;Install and configure the device-agent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the &lt;strong&gt;service&lt;/strong&gt; account, to do so open a command prompt window and run the following and authenticate:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-134&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-134&quot; class=&quot;language-bash&quot;&gt;runas /user:&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;serviceuser&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; cmd&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# e.g. runas /user:winserv cmd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-134&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;where &lt;code&gt;{serviceuser}&lt;/code&gt; is the service account (not the admin account)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;check-the-users-npm-global-path-is-set-in-the-users-environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#check-the-users-npm-global-path-is-set-in-the-users-environment-variables&quot;&gt;Check the users npm global path is set in the Users Environment Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;NOTE: The recommended flowfuse-device-agent instructions will result in the flowfuse-device-agent being installed in the NPM global directory.  And the instructions to launch the device-agent expect the NPM global directory to be in your user path.  This section will instruct you to a) find the NPM global path, then b) check the user’s path setting and, if necessary c) add the NPM global path to your user path.&lt;/p&gt;
&lt;p&gt;First, make a note of the path currently set for npm global. You can do this by running the following command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-147&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-147&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; config get prefix&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-147&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Next, ensure the &lt;code&gt;Path&lt;/code&gt; Variable under the &amp;quot;User variables for &lt;em&gt;user&lt;/em&gt;&amp;quot; contains the npm global path that we obtained in the previous step.
Use the below command, to check the user’s &lt;code&gt;Path&lt;/code&gt; setting.  If it is not present, edit the path to include it.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-151&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-151&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# This commands opens the environment variables editor, &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# look for the &quot;Path&quot; variable under &quot;User variables for user&quot;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# and ensure it contains the npm global path&lt;/span&gt;&lt;br /&gt;rundll32 sysdm.cpl,EditEnvironmentVariables&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-151&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;If you did have to add the npm path to the users &lt;code&gt;Path&lt;/code&gt; variable, you will need to &lt;strong&gt;restart&lt;/strong&gt; the command prompt for the change to take effect and relogin as &lt;strong&gt;user&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;install-the-device-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#install-the-device-agent&quot;&gt;Install the device agent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Note: you may have already installed the device-agent, however, &lt;strong&gt;we strongly recommend&lt;/strong&gt; you do this step again as the service account and ensure that account has the latest version.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-161&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-161&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @flowfuse/device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-161&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;link-the-device-agent-to-your-flowfuse-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#link-the-device-agent-to-your-flowfuse-team&quot;&gt;Link the device-agent to your flowfuse team&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we must run the device-agent and link it to our FlowFuse team.  This will generate a &amp;quot;device configuration&amp;quot; details that we will use to configure the device-agent.
Below is how to run the device-agent with the UI enabled.  This will allow you to configure the device-agent via its web UI.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-168&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-168&quot; class=&quot;language-bash&quot;&gt;flowfuse-device-agent &lt;span class=&quot;token parameter variable&quot;&gt;--ui&lt;/span&gt; --ui-port &lt;span class=&quot;token number&quot;&gt;8080&lt;/span&gt; --ui-user admin --ui-pass admin &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;flowfuse-device &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1880&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-168&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The device-agent will now be running and you can access the UI at &lt;a href=&quot;http://127.0.0.1:8080/&quot;&gt;http://127.0.0.1:8080&lt;/a&gt; with the user and password both &amp;quot;admin&amp;quot; (you can change these in the command line if required).
&lt;em&gt;NOTE: These credentials are temporary and only valid during the device setup&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Proceed to configure the device-agent and link it to your flowfuse team. Full instructions can be found &lt;a href=&quot;https://flowfuse.com/docs/device-agent/register/&quot;&gt;here&lt;/a&gt;.
Once you have linked the device-agent to your team, you can stop it by pressing &lt;code&gt;ctrl+c&lt;/code&gt; in the command prompt window.&lt;/p&gt;
&lt;h2 id=&quot;create-the-device-agent-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#create-the-device-agent-service&quot;&gt;Create the device-agent service&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the admin user, open an elevated command prompt see &lt;a href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#tip%3A-launching-an-elevated-command-prompt-window-(e.g.-as-the-admin-user)&quot;&gt;TIP&lt;/a&gt; above&lt;/p&gt;
&lt;h3 id=&quot;install-device-agent-as-a-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#install-device-agent-as-a-service&quot;&gt;Install device-agent as a service&lt;/a&gt;&lt;/h3&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-184&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-184&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; c:&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;opt&lt;br /&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;nssm.exe &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; flowfuse-device-agent &lt;span class=&quot;token string&quot;&gt;&quot;flowfuse-device-agent.cmd&quot;&lt;/span&gt;&lt;br /&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;nssm.exe &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; flowfuse-device-agent AppDirectory &lt;span class=&quot;token string&quot;&gt;&quot;c:&#92;opt&lt;span class=&quot;token entity&quot; title=&quot;&#92;f&quot;&gt;&#92;f&lt;/span&gt;lowfuse-device&quot;&lt;/span&gt;&lt;br /&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;nssm.exe &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; flowfuse-device-agent Description &lt;span class=&quot;token string&quot;&gt;&quot;FlowFuse Device Agent&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# set the AppParameters (cli options) to tell the agent where its home directory is&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# in our case, this is c:&#92;opt&#92;flowfuse-device and is set with the -d option&lt;/span&gt;&lt;br /&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;nssm.exe &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; flowfuse-device-agent AppParameters &lt;span class=&quot;token string&quot;&gt;&quot;-d c:&#92;opt&lt;span class=&quot;token entity&quot; title=&quot;&#92;f&quot;&gt;&#92;f&lt;/span&gt;lowfuse-device -p 1880&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-184&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;check-the-service-is-installed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#check-the-service-is-installed&quot;&gt;Check the service is installed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run the following command to check the service is installed:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-191&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-191&quot; class=&quot;language-bash&quot;&gt;services.msc&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-191&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;(look for a service named `flowfuse-device-agent&#39;).&lt;/p&gt;
&lt;p&gt;Alternatively, you can use the &lt;code&gt;sc&lt;/code&gt; command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-198&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-198&quot; class=&quot;language-bash&quot;&gt;sc query flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-198&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;set-the-user-account-that-will-run-the-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#set-the-user-account-that-will-run-the-service&quot;&gt;Set the user account that will run the service&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some things are easier to edit in the UI, so we will edit the service via the NSSM UI.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-205&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-205&quot; class=&quot;language-bash&quot;&gt;nssm edit flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-205&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;nssm editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nssm_service_editor.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In the UI, you can edit the service name, description, startup type, etc.
The most important thing to check is the &lt;code&gt;Application&lt;/code&gt; tab. This includes the path to the flowfuse-device-agent.cmd and its arguments.
Select the &amp;quot;Log on&amp;quot; tab, select &amp;quot;This account&amp;quot; and enter the service account name and password that will run the device-agent.
Click the &amp;quot;Edit Service&amp;quot; button to save the changes.&lt;/p&gt;
&lt;p&gt;Now you have a service that will run the device-agent as the &lt;strong&gt;service&lt;/strong&gt; account 🎉&lt;/p&gt;
&lt;h3 id=&quot;controlling-the-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#controlling-the-service&quot;&gt;Controlling the service&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can start the service with the command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-221&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-221&quot; class=&quot;language-bash&quot;&gt;sc start flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-221&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can check the current status with the command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-225&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-225&quot; class=&quot;language-bash&quot;&gt;sc query flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-225&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can stop the service with the command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-229&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-229&quot; class=&quot;language-bash&quot;&gt;sc stop flowfuse-device-agent&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-229&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/device-agent-as-a-windows-service/#further-reading&quot;&gt;Further reading&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;d like to learn about windows services via the &lt;code&gt;sc&lt;/code&gt; command you can access
the help text by running &lt;code&gt;sc&lt;/code&gt; from a command prompt.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/dashboard-0-10-0/</id>
        <title>Building a Custom Video Player in Dashboard 2.0</title>
        <summary>We&#39;ve just released the latest version of Dashboard 2.0, with a fully featured UI Templates node which now allows for full definition of a Vue component, external JS dependencies and CSS.</summary>
        <updated>2023-12-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/dashboard-0-10-0/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Dashboard 2.0 just got &lt;em&gt;a lot&lt;/em&gt; more powerful with our new updates to the &lt;code&gt;ui-template&lt;/code&gt; node. New features added to the node include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for a full Vue component  to be defined using the VueJS Options API.&lt;/li&gt;
&lt;li&gt;Running of raw JavaScript within &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; tags&lt;/li&gt;
&lt;li&gt;Loading of external dependencies through &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; tags&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article we&#39;re going to deepdive into an example of how you can use this new functionality to build a custom video player.&lt;/p&gt;
&lt;p&gt;We&#39;re going to aim for 3 key features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Emit events into Node-RED when a user plays/pauses the video&lt;/li&gt;
&lt;li&gt;Allow for the video to be played/paused from within Node-RED&lt;/li&gt;
&lt;li&gt;Allow the user to seek to a specific point in the video from within Node-RED&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #fff4b9; border:1px solid #ffc400; color: #a27110; padding: 12px; border-radius: 6px; font-style: italic;&quot;&gt;Reminder: all new releases of Dashboard are now under the &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowfuse&lt;/code&gt; namespace, so you&#39;ll need to update to use &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowfuse/node-red-dashboard&lt;/code&gt;, and not &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowforge&lt;/code&gt;.&lt;/div&gt;
&lt;h2 id=&quot;building-a-vue-component&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#building-a-vue-component&quot;&gt;Building a Vue Component&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With Dashboard 2.0, we switched over our underlying front-end framework to VueJS. We&#39;re aware that not everyone coming into Dashboard 2.0 will be familiar with VueJS.&lt;/p&gt;
&lt;p&gt;We have a more detailed guide &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#building-full-vue-components&quot;&gt;here&lt;/a&gt;, but we&#39;ll also give a quick overview of the elements from Vue &amp;quot;component&amp;quot; that we&#39;ll use here:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-53&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-53&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Our HTML content will go here --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MyComponent&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// JS methods we want to use across our component will go here&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Code we want to run when our component is loaded will go here&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;unmounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Code we want to run when our component is unloaded will go here&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* We can define custom CSS here too */&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-53&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Some quick gotchas to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div&amp;gt;{{ msg }}&amp;lt;/div&amp;gt;&lt;/code&gt; - is an example of how you render variables into the HTML.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div v-if=&amp;quot;myVar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; - lets you conditionally show/hide content based on a variable.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div v-for=&amp;quot;item in items&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; - lets you loop over an array of items and render them into the HTML.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div @click=&amp;quot;myMethod&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; - lets you bind a method to an event, in this case, when the user clicks on the div.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;div :class=&amp;quot;{ &#39;my-class&#39;: isActive }&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; - &lt;code&gt;:&lt;/code&gt; is a way to define a &amp;quot;bound&amp;quot; property. In this case, the class &lt;code&gt;my-class&lt;/code&gt; will be applied when &lt;code&gt;isActive&lt;/code&gt; is true.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;console.log(this.myVar)&lt;/code&gt; - when you&#39;re writing code inside the &lt;code&gt;&amp;lt;script /&amp;gt;&lt;/code&gt; tags, you can access Component variables and methods using &lt;code&gt;this&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;built-in-extras&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#built-in-extras&quot;&gt;Built-in Extras&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to building a component from scratch, we&#39;ll also utilize some built-in features of &lt;code&gt;ui-template&lt;/code&gt; too. These will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Variables:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt; - The unique ID for this node in Node-RED&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msg&lt;/code&gt; - The message that was most recently received into the node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$socket&lt;/code&gt; - The underlying SocketIO connection to Node-RED. Use this to listen to any incoming events, and send new ones back.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functions:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;send(payload)&lt;/code&gt; - Send a message back to Node-RED&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As above, we have more detailed documentation on these features &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#built-in-functionality&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-the-video-player&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#building-the-video-player&quot;&gt;Building the Video Player&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;defining-the-content-(html)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#defining-the-content-(html)&quot;&gt;Defining the Content (HTML)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re going to start by adding a basic HTML video player:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-143&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-143&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;video&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-video&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;controls&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;@play&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;onPlay&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;@pause&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;onPause&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;video/mp4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        Your browser does not support the video tag.&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;video&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-143&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;A few things of importance to note here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ref&lt;/code&gt; is Vue&#39;s replacement for &lt;code&gt;document.getElementById()&lt;/code&gt;. This is copied to each instance of the component, meaning we can call &lt;code&gt;this.$refs[&#39;my-video&#39;]&lt;/code&gt; to access the video element, and this doesn&#39;t break when duplicating the widget multiple times in Dashboard.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style=&amp;quot;&amp;quot;&lt;/code&gt; is required here to ensure the video fills the group/wrapper that it is contained within.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@play=&lt;/code&gt; is Vue&#39;s way of binding onto the standard &lt;code&gt;onplay&lt;/code&gt; event listener available on HTML video players. We&#39;ll define the &lt;code&gt;onPlay&lt;/code&gt; method in the next section.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@pause=&lt;/code&gt; is our event listener for when the video is paused by the user. As with &lt;code&gt;onPlay&lt;/code&gt;, we&#39;ll define this shortly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;em&gt;just&lt;/em&gt; the above defined, we end up with a standard video player rendered:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;HTML5 Video Player rendered in Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-video-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;defining-the-behaviors-(vuejs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#defining-the-behaviors-(vuejs)&quot;&gt;Defining the Behaviors (VueJS)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we begin to build our Vue component. Referring back to our earlier set of features, we&#39;ll tackle these one at a time.&lt;/p&gt;
&lt;h4 id=&quot;1.-emitting-events-to-node-red-on-play%2Fpause&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#1.-emitting-events-to-node-red-on-play%2Fpause&quot;&gt;1. Emitting Events to Node-RED on Play/Pause&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;We can use &lt;code&gt;methods&lt;/code&gt; to define our &lt;code&gt;onPlay&lt;/code&gt; and &lt;code&gt;onPause&lt;/code&gt; functions that are called &lt;code&gt;@play&lt;/code&gt;/&lt;code&gt;@pause&lt;/code&gt; respectively.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-187&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-187&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MyVideoPlayer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;capture&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eventType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// let&#39;s define our own function that can be called onPlay/onPause&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// this prevents duplicated code across the two methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// get the Video&#39;s DOM element&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; video &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$refs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-video&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// send a msg to Node-RED using built-in &quot;send&quot; fcn&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// specify which action is taking place&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; eventType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// use Vue&#39;s $refs to get the video&#39;s currentTime&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;onPlay&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;capture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;play&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;onPause&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;capture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pause&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-187&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;With this functionality in place, we can wire the &lt;code&gt;ui-template&lt;/code&gt; node to a &lt;code&gt;debug&lt;/code&gt; node, and see the following when we play/pause the video:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Example debug output when our custom build video player is played/paused&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-video-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;2.-remote-control-of-play%2Fpause-from-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#2.-remote-control-of-play%2Fpause-from-node-red&quot;&gt;2. Remote control of play/pause from Node-RED&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;We can use the built-in &lt;code&gt;$socket&lt;/code&gt; variable to listen for incoming events from Node-RED. When Dashboard 2.0&#39;s nodes receive a &lt;code&gt;msg&lt;/code&gt; inside Node-RED, they send a &lt;code&gt;msg-input:&amp;lt;node-id&amp;gt;&lt;/code&gt; event to the Dashboard client. We can listen for this event and then call the &lt;code&gt;play()&lt;/code&gt; and &lt;code&gt;pause()&lt;/code&gt; methods on the video element, depending on any properties of that message, in this case, the &lt;code&gt;msg.payload.event&lt;/code&gt; value.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-200&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-200&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MyVideoPlayer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// listen for incoming msg&#39;s from Node-RED&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// note our topic is &quot;msg-input&quot; + the node&#39;s unique ID&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;msg-input:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// get the Video&#39;s DOM element&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; video &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$refs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-video&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// if the event is &quot;play&quot;, call the video&#39;s play() method&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;event &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;play&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// if the event is &quot;pause&quot;, call the video&#39;s pause() method&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;event &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;pause&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;unmounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// make sure we remove our listeners when the widget is destroyed&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;msg-input:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-200&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;3.-seeking-to-a-specific-point-in-the-video-from-within-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#3.-seeking-to-a-specific-point-in-the-video-from-within-node-red&quot;&gt;3. Seeking to a specific point in the video from within Node-RED&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;With the &lt;code&gt;on(&#39;msg-input&#39;)&lt;/code&gt; listener in place, we can now extend our handler to handle seeking to a specific point in the video.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-207&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-207&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MyVideoPlayer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;msg-input:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// ... other handlers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// if the event is &quot;seek&quot;, call the video&#39;s currentTime() method&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;event &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;seek&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            video&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;unmounted&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-207&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;and with that, we now have a Dashboard 2.0 widget to display a video, that can be controlled from Node-RED, and logs details of user activity back into Node-RED.&lt;/p&gt;
&lt;p&gt;Other features available with the UI Template are detailed in the online documentation, and include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#loading-external-dependencies&quot;&gt;Loading External Dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html#writing-raw-javascript&quot;&gt;Running raw JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/dashboard-0-10-0/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can also read the more comprehensive release notes for &lt;code&gt;v0.10.0&lt;/code&gt; release here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.10.0&quot;&gt;0.10.0 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As always, thanks for reading and your interest in Dashboard 2.0. If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/12/ai-use-cases/</id>
        <title>Beyond Automation - AI Use Cases that are shaping the next manufacturing frontier</title>
        <summary>In which AI-powered capabilities should one invest to bring about transformative changes in the manufacturing environment?</summary>
        <updated>2023-12-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/12/ai-use-cases/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Are we standing on the brink of a Fifth Industrial Revolution? The manufacturing industry has been in a state of flux for some time, with the rise of automation and digital transforming the way factories operate. But today, we are witnessing something even more profound: AI is pushing manufacturing to a whole new level. Some have even referred to it as “the fifth industrial revolution” due to its potential for disruption.&lt;/p&gt;
&lt;p&gt;But the question lingers for many plant managers and decision makers: in which AI-powered capabilities should one invest to bring about transformative changes in the manufacturing environment?&lt;/p&gt;
&lt;p&gt;As we navigate this question, I want to focus on three AI uses that are not only ripe for investment but also pivotal in driving manufacturing success in this competitive market.&lt;/p&gt;
&lt;h2 id=&quot;empowering-citizen-developer-strategy-with-ai&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/ai-use-cases/#empowering-citizen-developer-strategy-with-ai&quot;&gt;Empowering Citizen Developer Strategy with AI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The concept of citizen development stands as one of the most significant fields in my opinion, a sentiment I&#39;ve detailed in my &lt;a href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/&quot;&gt;previous article&lt;/a&gt; about Citizen Developers. This approach is revolutionizing the manner in which applications are crafted and deployed across various industries. By empowering individuals—irrespective of their coding knowledge—to create applications, AI is dramatically hastening this process.&lt;/p&gt;
&lt;p&gt;Investing in AI capabilities that bolster your citizen developer strategy can fast-track application development, offering intuitive, template-driven platforms that employ AI to navigate users through the creation process. As we&#39;ve seen over recent months and years, AI can significantly assist in code generation, thereby granting your citizen developers an even smoother initiation into application development.&lt;/p&gt;
&lt;p&gt;An excellent instance of this is the &lt;a href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/&quot;&gt;article and Node-RED Node&lt;/a&gt; describing the potential for integrating Node-RED with ChatGPT to assist you in building applications. This integration highlights the practical, user-friendly solutions made possible through AI, making the realm of app development accessible to a broader range of innovators.&lt;/p&gt;
&lt;h2 id=&quot;refining-warehouse-management-through-ai-driven-demand-forecasting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/ai-use-cases/#refining-warehouse-management-through-ai-driven-demand-forecasting&quot;&gt;Refining Warehouse Management through AI-Driven Demand Forecasting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In an era marked by complexities in supply chains and customer demand, AI&#39;s role in warehouse management becomes a game-changer. AI algorithms analyze historical data and market trends to predict future demand with astonishing accuracy, a step beyond traditional forecasting methods.&lt;/p&gt;
&lt;p&gt;For decision makers, investing in AI for demand forecasting means significantly minimizing overproduction or stock outs, optimizing inventory levels, and improving customer satisfaction. The advanced analytics offered by AI not only predict what products are in demand but also when and where they are needed, thereby facilitating strategic planning and resource allocation.&lt;/p&gt;
&lt;h2 id=&quot;elevating-predictive-maintenance-and-quality-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/ai-use-cases/#elevating-predictive-maintenance-and-quality-control&quot;&gt;Elevating Predictive Maintenance and Quality Control&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unplanned downtime and quality inconsistencies are two of the biggest profit drains in manufacturing. AI&#39;s predictive capabilities are setting new standards in both maintenance and quality control protocols. By continuously monitoring equipment performance and production processes, AI can predict and identify machinery failures before they occur and detect quality deviations in real-time—allowing for immediate correction. Investing here means less downtime, reduced maintenance costs, improved product quality, and ultimately, an enhanced bottom line.&lt;/p&gt;
&lt;h2 id=&quot;your-digital-infrastructure-%26-architecture-is-key&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/12/ai-use-cases/#your-digital-infrastructure-%26-architecture-is-key&quot;&gt;Your Digital Infrastructure &amp;amp; Architecture is key&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While understanding where concrete Use Cases are is crucial, it’s equally important to ensure that your digital strategy and architecture can support and quickly adapt to these advanced AI implementations. See also &lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/&quot;&gt;my article&lt;/a&gt; about the Unified Namespace. A flexible system that integrates a Unified Namespace is critical for seamless data exchange across various systems and applications. Moreover, fostering a citizen developer environment is fundamental in ensuring that these AI investments are maximally utilized, empowering your workforce to contribute actively to the company&#39;s innovation cycle.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/device-agent-balena/</id>
        <title>Deploying the FlowFuse Device Agent via Balena</title>
        <summary>Using Balena.io to Deploy fleets of devices</summary>
        <updated>2023-11-24T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/device-agent-balena/"/>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;As part of the FlowFuse Staff Summit this year in Barcelona we met up with Marc Pous from &lt;a href=&quot;https://www.balena.io/&quot;&gt;Balena Io&lt;/a&gt;. Balena is a platform for managing fleets of Edge Devices and it felt like the perfect fit for deploying the FlowFuse Device Agent.&lt;/p&gt;
&lt;p&gt;To do this you install the Balena OS on the devices, this is a stripped down Linux distribution that includes a client that connects back to Balena&#39;s platform and creates a VPN tunnel. As well as the Balena client it includes Docker and users can select containers to push to the devices.&lt;/p&gt;
&lt;p&gt;These Docker container are hosted on Balena&#39;s own container registry and are built by doing a git push to Balena&#39;s git server.&lt;/p&gt;
&lt;p&gt;A GitHub repository with all the required files &lt;a href=&quot;https://github.com/FlowFuse/balena-device-agent&quot;&gt;has been published&lt;/a&gt;, a one click deploy button to allow you to quickly try this out.&lt;/p&gt;
&lt;h2 id=&quot;building-flowfuse-device-agent-for-balena&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#building-flowfuse-device-agent-for-balena&quot;&gt;Building FlowFuse Device Agent for Balena&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We already build a FlowFuse Device Agent Docker container so it was pretty simple to modify the existing &lt;code&gt;Dockerfile&lt;/code&gt; for Balena.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-18&quot;&gt;
  &lt;pre class=&quot;language-docker&quot;&gt;&lt;code id=&quot;code-18&quot; class=&quot;language-docker&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; balenalib/%%BALENA_MACHINE_NAME%%-alpine-node&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; mkdir /opt/flowfuse-device&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; npm install -g @flowfuse/device-agent&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; entrypoint.sh /usr/src/entrypoint.sh&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENTRYPOINT&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;/usr/src/entrypoint.sh&quot;&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CMD&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;flowfuse-device-agent&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-18&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;There were 2 main changes from the default Device Agent &lt;a href=&quot;https://github.com/FlowFuse/device-agent/blob/main/docker/Dockerfile&quot;&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Change the base image to Balena&#39;s image, this is because the &lt;code&gt;Dockerfile&lt;/code&gt; is actually a template that can be used to build images optimized for all Balena&#39;s supported hardware platforms (We currently build the FlowFuse Device Agent containers for AMD64, ARMv7 and ARM64)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adding a custom &lt;code&gt;entrypoint.sh&lt;/code&gt;. This is to ensure that the hostname seen in the container matches the Balena device name, making it easier to match it up with what is seen in the FlowFuse application. It also generates the configuration file from the passed in environment variable (see &lt;a href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#configuring-devices&quot;&gt;below&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As well as the &lt;code&gt;Dockerfile&lt;/code&gt; there is also a &lt;code&gt;docker-compose.yml&lt;/code&gt; because Balena applications can be made up of multiple services packaged as container. In this case we just need a single container but the compose file contains all the information about what ports to expose and what volumes need creating to persist state.&lt;/p&gt;
&lt;h2 id=&quot;configuring-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#configuring-devices&quot;&gt;Configuring Devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The FlowFuse Device agent can be configured in 2 ways.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You can provide a configuration file that is provided by the FlowFuse application when you create a new Device. This file contains the unique identifiers for the Device and details of where to find the FlowFuse Application. This file can be provided to a Balena device by adding a device specific environment variable as described &lt;a href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#environment-variable&quot;&gt;below&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can provide a fleet of devices with a configuration file that contains details of where to find the FlowFuse application and a Provisioning token. Multiple Devices can all have the same Provisioning token and this will cause them to connect to the FlowFuse application on first start up and create a new Device bound to an existing team (and optionally an Application or Instance). This file can be passed to Balena devices by way of a Fleet wide environment variable as described &lt;a href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#environment-variable&quot;&gt;below&lt;/a&gt;.
You can create a Provisioning Token file under the Team -&amp;gt; Settings page on the Devices tab.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;environment-variable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/device-agent-balena/#environment-variable&quot;&gt;Environment Variable&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because the &lt;code&gt;device.yml&lt;/code&gt; file is multi line it needs to be base64 encoded, you can do this with the following&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-61&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-61&quot; class=&quot;language-bash&quot;&gt;$ base64 &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; device.yml&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-61&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;You can then use the Balena console to create either a device specific or a fleet wide environment variable called &lt;code&gt;FF_DEVICE_YML&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;balena-env-var&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/balena-env-var.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/dashboard-0-8-0/</id>
        <title>Overhauling the Dashboard 2.0 Build Pipeline</title>
        <summary>A month or so ago, we released the Third-Party widget support for Dashboard 2.0, but having seen the feedback, we missed the beat, so we&#39;ve built it again!</summary>
        <updated>2023-11-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/dashboard-0-8-0/"/>
        <author><name></name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;As a developer, sometimes you have to hold up your hands and realise something you&#39;ve spent two weeks building needs to be thrown away and restarted.&lt;/p&gt;
&lt;p&gt;Having shipped the &lt;a href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/&quot;&gt;third-party widget support for Dashboard 2.0&lt;/a&gt; in line with Dashboard 1.0&#39;s approach, we then had the &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/307&quot;&gt;feedback&lt;/a&gt; that the way Dashboard 1.0 did things really wasn&#39;t good, and asking us to consider re-building the process to make the developer experience of working with Dashboard 2.0 far more seamless.&lt;/p&gt;
&lt;p&gt;So, that&#39;s exactly what we&#39;ve done with the &lt;code&gt;0.8.0&lt;/code&gt; release, amongst a few other things.&lt;/p&gt;
&lt;div style=&quot;background-color: #fff4b9; border:1px solid #ffc400; color: #a27110; padding: 12px; border-radius: 6px; font-style: italic;&quot;&gt;Reminder: all new releases of Dashboard are now under the &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowfuse&lt;/code&gt; namespace, so you&#39;ll need to update to use &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowfuse/node-red-dashboard&lt;/code&gt;, and not &lt;code style=&quot;background-color: transparent;&quot;&gt;@flowforge&lt;/code&gt;.&lt;/div&gt;
&lt;h2 id=&quot;migrating-our-build-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-8-0/#migrating-our-build-pipeline&quot;&gt;Migrating our Build Pipeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Without getting &lt;em&gt;too&lt;/em&gt; technical, as part of this work in supporting third-party widgets, we overhauled our build pipeline for Dashboard 2.0. This pipeline is responsible for taking our source code, and compiling it into a format that then gets deployed by Node-RED when running Dashboard.&lt;/p&gt;
&lt;p&gt;Previously, we used &lt;em&gt;&lt;strong&gt;Webpack&lt;/strong&gt;&lt;/em&gt;, but now, we&#39;ve switched over to &lt;em&gt;&lt;strong&gt;Vite&lt;/strong&gt;&lt;/em&gt;. This is a newer build tool, and is much faster than Webpack. It&#39;s also what we&#39;ve now updated out &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard-2-ui-example&quot;&gt;Example Node&lt;/a&gt; to use too.&lt;/p&gt;
&lt;p&gt;So now, when working with a third-party widget, Vite builds up all of your code, wraps it into a single &lt;code&gt;umd.js&lt;/code&gt; file, and Node-RED then serves that file up for Dashboard 2.0 to load in.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Vite Build Process&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-build.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also re-written our &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/widgets/third-party.html&quot;&gt;&amp;quot;Building Third Party Widgets&amp;quot;&lt;/a&gt; guide to reflect this change.&lt;/p&gt;
&lt;h2 id=&quot;debugging-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-8-0/#debugging-dashboard&quot;&gt;Debugging Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A new feature we&#39;ve added in &lt;code&gt;0.8.0&lt;/code&gt; is also for those developing Dashboard&#39;s core and third-party widgets. You can now navigate to &lt;code&gt;/dashboard/_debug&lt;/code&gt; to explore the full configuration that Dashboard receives from Node-RED.&lt;/p&gt;
&lt;p&gt;This is particularly useful when you&#39;re trying to debug why a widget isn&#39;t loading, showing the correct data, or generally isn&#39;t behaving as you expect.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Dashboard&#39;s Debug View&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/debug-view.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Note in the above example, where we can see that the &lt;code&gt;ui-dropdown&lt;/code&gt; has had it&#39;s options overriden by &lt;code&gt;msg.options&lt;/code&gt; on injection.&lt;/p&gt;
&lt;p&gt;You can read more about the debugging view &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/widgets/debugging.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new-in-0.8.0%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-8-0/#what-else-is-new-in-0.8.0%3F&quot;&gt;What else is new in 0.8.0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst we focussed this article on the build pipeline overhaul, changes to third-party wdgets and debugging Dashboard, we did also squeeze quite a lot more into the 0.8.0 releases too with plenty other fixes and improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/345&quot;&gt;Dynamic setting of msg.options for UI Dropdown&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/346&quot;&gt;&amp;quot;Date&amp;quot; type for UI Text Input&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/365&quot;&gt;Finer grain controls of Text Input event emissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/367&quot;&gt;Control over when UI Slider emits events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/364&quot;&gt;Improved documentation for Bar Charts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also read the more comprehensive release notes for the release here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.8.0&quot;&gt;0.8.0 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-8-0/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As always, thanks for reading and your interested in Dashboard 2.0. If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/ai-assistant/</id>
        <title>Integrate with ChatGPT Assistants with Node-RED</title>
        <summary>Get start quickly leveraging Flows utilizing ChatGPT Assistant</summary>
        <updated>2023-11-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/ai-assistant/"/>
        <author><name></name></author>
        <content type="html">&lt;h2 id=&quot;introduction-to-the-world-of-gpts-and-ai-assistants&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/ai-assistant/#introduction-to-the-world-of-gpts-and-ai-assistants&quot;&gt;Introduction to the World of GPTs and AI Assistants&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the ever-evolving landscape of artificial intelligence, Generative Pre-trained Transformers (GPTs) have emerged as groundbreaking tools. These advanced AI models, developed by OpenAI, are capable of understanding and generating human-like text, offering vast possibilities across numerous applications. GPTs learn from various internet texts, enabling them to respond to queries with human-like understanding.&lt;/p&gt;
&lt;p&gt;Among the most intriguing developments in this field are AI Assistants. These are specialized applications of GPTs, accessible through an API, designed to enhance and streamline various tasks. Tasks that include code interpreter, functions, retrieval, and leveraging uploading files to interact with. Unlike traditional GPTs, which primarily focus on generating text, AI Assistants can interact, comprehend, and assist in real-time, making them invaluable in industries ranging from manufacturing to finance to healthcare.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/flow/073548c276832e804f037f3212014e60&quot;&gt;TLDR: Give me the Flows&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;node-red-and-ai-assistants&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/ai-assistant/#node-red-and-ai-assistants&quot;&gt;Node-RED and AI Assistants&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The integration of Node-RED with AI Assistants brings a unique set of advantages. By leveraging Node-RED&#39;s user-friendly platform, developers and citizen developers can easily harness the power of AI Assistants. This integration allows for creation of bespoke solutions tailored to specific industry needs, ranging from automated customer service to advanced data analytics. The real-world impact is substantial – imagine a manufacturing line where real-time data is seamlessly integrated with a prescriptive AI-driven decision-making prompt, enhancing efficiency and reducing downtime.  In healthcare, it provides patients with real-time updates to their personal data and provides contextual information, while in retail, it could enhance customer engagement through personalized interactions. The future shaped by these technologies is one where automation and intelligence converge, leading to unprecedented levels of efficiency and innovation in various sectors.&lt;/p&gt;
&lt;h2 id=&quot;experience-the-integration-firsthand&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/ai-assistant/#experience-the-integration-firsthand&quot;&gt;Experience the Integration Firsthand&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We invite you to explore the possibilities firsthand. Try out the flows we&#39;ve created and share your feedback. This is your getting started package. In the provided flows, you can do the following:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;OpenAI Assistant integration on Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ai-flows.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create Assistant&lt;/strong&gt;: This flow creates a new assistant. It starts with an inject node that sets the assistant&#39;s name, instructions, tools, and model. The HTTP request node then sends a POST request to the OpenAI API to create the assistant. The assistant&#39;s ID is stored in the flow context for later use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List Assistants&lt;/strong&gt;: This flow lists all the assistants that have been created. It starts with an inject node that triggers the flow. The HTTP request node sends a GET request to the OpenAI API to retrieve the list of assistants. The results are then displayed in the debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Delete Assistant&lt;/strong&gt;: This flow deletes an assistant. It starts with an inject node that sets the assistant&#39;s ID. The template node constructs the URL for the HTTP request node, which sends a DELETE request to the OpenAI API to delete the assistant. The results are then displayed in the debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adjust Assistant Instructions and Models&lt;/strong&gt;: This flow adjusts the instructions and model of an assistant. It starts with an inject node that sets the assistant&#39;s ID, new instructions, and new model. The change node prepares the payload for the HTTP request node, which sends a POST request to the OpenAI API to update the assistant. The results are then displayed in the debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create Thread and Run&lt;/strong&gt;: This flow creates a new thread and runs it. It starts with an inject node that sets the assistant&#39;s ID and the message to be sent. The subflow node then handles the creation of the thread, sending of the message, and retrieval of the response. The results are then displayed in the debug node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How do you envision leveraging this integration in your day-to-day operations or within your industry? Your insights are valuable in shaping the future of our industry. Begin your journey &lt;a href=&quot;https://flows.nodered.org/flow/073548c276832e804f037f3212014e60&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;embracing-the-future-of-ai-and-automation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/ai-assistant/#embracing-the-future-of-ai-and-automation&quot;&gt;Embracing the Future of AI and Automation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Integrating Node-RED with OpenAI&#39;s Assistants is a testament to the ever-evolving landscape of technology. It represents a step towards a future where powerful AI tools are within reach of a wider audience, enabling the creation of bespoke, flexible, and resilient applications across industries. By embracing this integration, we open doors to innovation and efficiency previously unimagined.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Always consult with management before uploading company data to public services like ChatGPT.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/chatgpt-gpt/</id>
        <title>Node-RED Builder a GPT (Alpha) by FlowFuse</title>
        <summary>Speed Up Flow Creation with Your Personal Assistant</summary>
        <updated>2023-11-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/chatgpt-gpt/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;When ChatGPT was first released, my expectations were quite low. I had grown accustomed to the usual industry buzz for AI and ML that often led to underwhelming solutions. Naturally, I approached ChatGPT with similar reservations. It wasn&#39;t until a few months after its announcement that I decided to give it a try. To my surprise, within just 10 minutes, I found myself so captivated that I decided to purchase the pro version.&lt;/p&gt;
&lt;p&gt;On November 6th, OpenAI unveiled a new offering: GPTs. These function as custom ChatGPT environments, allowing the author to provide additional context, giving it a specific and focused purpose. With new content emerging daily for both Node-RED and FlowFuse, the ability to update and provide essential documentation became increasingly valuable.&lt;/p&gt;
&lt;p&gt;ChatGPT is already a fantastic tool for building Node-RED flows, and if you haven&#39;t tried it yet, I highly recommend giving it a go. Now, let me introduce you to Node-RED Builder, a preconfigured environment where all the necessary prompts are already set up to ensure your success. Furthermore, the latest knowledge on Node-RED and FlowFuse is readily available within the GPT, allowing you to tap into the most up-to-date documentation for your prompts.&lt;/p&gt;
&lt;p&gt;Node-RED Builder streamlines the development of Node-RED flows, making it more accessible, especially for those new to this environment. We&#39;ve even provided context to emphasize the use of default nodes over function nodes. Imagine being able to simply drag and drop elements, connect nodes, and create functional flows without delving deep into complex coding. This is precisely what Node-RED Builder makes easier, effectively opening the doors of Node-RED to a wider audience.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://chat.openai.com/g/g-V5Kyn4omE-node-red-builder-by-flowfuse-v1-0-2&quot;&gt;Access to the GPT - Node-RED builder by FlowFuse&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/dashboard-2.0-user-tracking/</id>
        <title>Tracking Who Has Opened a Dashboard</title>
        <summary>Using FlowFuse Authentication Audit Dashboard v2 Access</summary>
        <updated>2023-11-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/dashboard-2.0-user-tracking/"/>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;As we continue to add features to the Node-RED Dashboard v2 one feature request that came in was to track which users had visited a Dashboard. Multi user support for the Dashboard is on the backlog but this could be solved with the parts that are currently available.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-authentication&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-2.0-user-tracking/#flowfuse-authentication&quot;&gt;FlowFuse Authentication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the features we offer on FlowFuse is the ability to protect HTTP endpoints and Dashboards using the same FlowFuse user authentication that protects access to the FlowFuse Application and the Node-RED instances.&lt;/p&gt;
&lt;p&gt;We even offer a specific RBAC &#39;viewer&#39; role that just allows access to these endpoints but not the FlowFuse application.&lt;/p&gt;
&lt;p&gt;FlowFuse authentication can be enabled from the Instance Settings page on the Security tab&lt;/p&gt;
&lt;p&gt;This can be used to secure access to a Dashboard hosted in a Node-RED Instance. At the moment the Dashboard while protected by this authentication, it is not aware of which user is accessing it.&lt;/p&gt;
&lt;p&gt;But if we include an element in the Dashboard loaded via a HTTP-in/HTTP-response node we gain access to details of the authenticated user.&lt;/p&gt;
&lt;h2 id=&quot;implementation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-2.0-user-tracking/#implementation&quot;&gt;Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First we will create a HTTP-in/HTTP-response pair to serve up a single pixel SVG image. I chose SVG as it doesn&#39;t require creating a binary image file to load.&lt;/p&gt;
&lt;p&gt;The following flow snippet includes both the HTTP-in/HTTP-response nodes and a change node to set the &lt;code&gt;msg.payload&lt;/code&gt; to the SVG content and to set the HTTP headers to include the correct mime type.&lt;/p&gt;
&lt;p&gt;There is also a second change node which extracts the user information.&lt;/p&gt;
&lt;div id=&quot;nr-flow-175&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow175 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;7f22dc81d8192d4d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;98c8d7ea66149291&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;/tracker&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;get&#92;&quot;,&#92;&quot;upload&#92;&quot;:false,&#92;&quot;swaggerDoc&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7d36739c02cd04ec&#92;&quot;,&#92;&quot;5f4647c97917cce1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;58fd30516a077e29&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;98c8d7ea66149291&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusCode&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;headers&#92;&quot;:{},&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7d36739c02cd04ec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;98c8d7ea66149291&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&amp;lt;svg width=&#92;&#92;&#92;&quot;1&#92;&#92;&#92;&quot; height=&#92;&#92;&#92;&quot;1&#92;&#92;&#92;&quot;&amp;gt; &amp;lt;rect width=&#92;&#92;&#92;&quot;1&#92;&#92;&#92;&quot; height=&#92;&#92;&#92;&quot;1&#92;&#92;&#92;&quot; style=&#92;&#92;&#92;&quot;fill:rgb(255,255,255);stroke-width:3;stroke:rgb(0,0,0)&#92;&#92;&#92;&quot; /&amp;gt; Sorry, your browser does not support inline SVG.&amp;lt;/svg&amp;gt;&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;headers&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;{&#92;&#92;&#92;&quot;Content-Type&#92;&#92;&#92;&quot;:&#92;&#92;&#92;&quot;image/svg+xml&#92;&#92;&#92;&quot;}&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;58fd30516a077e29&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5f4647c97917cce1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;98c8d7ea66149291&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;req.session.user&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ddc02b4e9c30c807&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ddc02b4e9c30c807&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;98c8d7ea66149291&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:600,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow175.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-175&#39;) })&lt;/script&gt;
&lt;p&gt;Next we need to add the SVG to the Dashboard, this can be done by adding a Template node with the following HTML content.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-37&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-37&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/tracker&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-37&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will load the image every time the Dashboard page loads and hence trigger the earlier flow allowing the user to be logged.&lt;/p&gt;
&lt;h2 id=&quot;linking-to-sso-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-2.0-user-tracking/#linking-to-sso-users&quot;&gt;Linking to SSO Users&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the release of FlowFuse v1.14.0 the session object will also include the users email address which is the shared identifier between FlowFuse and the SSO system. This will allow the logging to use a single unified identifier.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/dashboard-0-7/</id>
        <title>Chart Improvements &amp; Migrating to Dashboard 2.0</title>
        <summary>With the 0.7.x Releases of Dashboard 2.0, we&#39;ve made big improvements to Charts, generated a migration guide, and much more...</summary>
        <updated>2023-11-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/dashboard-0-7/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It&#39;s been a little while since we&#39;ve done an update, since we last posted we&#39;ve moved into the 0.7.x releases for Dashboard 2.0. With these we&#39;re making big strides in improving the UX for charting your data, as well as starting to focus on migration paths from Dashboard 1.0 to 2.0.&lt;/p&gt;
&lt;h2 id=&quot;package-name-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#package-name-changes&quot;&gt;Package Name Changes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Firstly a bit of news regarding the &lt;code&gt;npm&lt;/code&gt; package we publish. Inline with our own &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/&quot;&gt;company name change&lt;/a&gt;, we&#39;ve had to update Dashboard 2.0&#39;s npm package, and so, we&#39;ve changed from &lt;code&gt;@flowforge/node-red-dashboard&lt;/code&gt; to &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the short term, we&#39;ll be keeping @flowforge available on the Node-RED Palette Manager, but it will be removed soon, and the associated NPM Package will be put into a &amp;quot;deprecated&amp;quot; mode.&lt;/p&gt;
&lt;h3 id=&quot;npm-package-migration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#npm-package-migration&quot;&gt;NPM Package Migration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, this migration from &lt;code&gt;@flowforge/&lt;/code&gt; to &lt;code&gt;@flowfuse/&lt;/code&gt; requires a little bit of manual work, and isn&#39;t as easy as just clicking &amp;quot;update&amp;quot; in the Node-RED Editor.&lt;/p&gt;
&lt;p&gt;In any case, there is no need to update your flow in this migration, you&#39;ll just need to uninstall &lt;code&gt;@flowforge/node-red-dashboard&lt;/code&gt; and install &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; instead.&lt;/p&gt;
&lt;h4 id=&quot;running-locally&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#running-locally&quot;&gt;Running Locally&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you&#39;re running Node-RED locally, or in your own infrastructure, you&#39;ll need to manually uninstall the old package:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-27&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-27&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; uninstall @flowforge/node-red-dashboard&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-27&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;and re-install the new one:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-31&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-31&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; @flowfuse/node-red-dashboard&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-31&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h4 id=&quot;running-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#running-in-flowfuse&quot;&gt;Running in FlowFuse&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Navigate to your Instance &amp;gt; Settings &amp;gt; Palette, and then change the &lt;code&gt;@flowforge/node-red-dashboard&lt;/code&gt; entry to &lt;code&gt;@flowfuse/node-red-dashboard&lt;/code&gt; (the latest version as of this post is &lt;code&gt;0.7.2&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Restart your instance, and the new package will automatically install.&lt;/p&gt;
&lt;h2 id=&quot;dashboard-1.0-to-2.0-migration-guide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#dashboard-1.0-to-2.0-migration-guide&quot;&gt;Dashboard 1.0 to 2.0 Migration Guide&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As part of our mission to ensure a smooth transition from Dashboard 1.0 to Dashboard 2.0, we have published a first draft of a &lt;a href=&quot;https://dashboard.flowfuse.com/user/migration.html&quot;&gt;Migration Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a starting point, we have comprehesively covered the Dashboard 1.0 widgets and their associated properties. We&#39;ve then detailed which properties are already supported, which have partial support, and where appropriate, we do not support and &lt;em&gt;why&lt;/em&gt; (most of the time, it&#39;s just because we haven&#39;t got round to it yet!)&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Migration Guide Snippet&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/migration-guide-snippet.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We fully appreciate that the migration path is not yet complete, and we that we are missing some features and properties, but please know that we are working hard to ensure that as many of the features from Dashboard 1.0 are available in Dashboard 2.0. We will be updating this guide as we progress.&lt;/p&gt;
&lt;p&gt;We will also be adding &amp;quot;event&amp;quot; and &amp;quot;dynamic properties&amp;quot; sections to the guide, to detail how you can update and control elements via runtime messages (e.g. dynamically change the label of a button), and how this differs (if at all) from Dashboard 1.0.&lt;/p&gt;
&lt;p&gt;Whilst we aren&#39;t quite there yet, this guide offers a comprehensive breakdown on our progress in backporting all of the properties from Dashboard 1.0&lt;/p&gt;
&lt;h3 id=&quot;automated-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#automated-script&quot;&gt;Automated Script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An ambitious plan that we have is to also provide a &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/261&quot;&gt;Migration Script&lt;/a&gt;. Any feedback, ideas or concerns are most welcome as comments on the issue.&lt;/p&gt;
&lt;p&gt;Whilst this will never provide 100% perfect migration, we hope to be able to provide a script that can be run against your flows to automatically convert as much as possible from Dashboard 1.0 to 2.0. In most cases, as you can see in the Migration guide, we match most properties 1:1, so this should do a lot of the heavy lifting for you.&lt;/p&gt;
&lt;h2 id=&quot;updates-to-ui-chart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#updates-to-ui-chart&quot;&gt;Updates to UI Chart&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;key-mapping&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#key-mapping&quot;&gt;Key Mapping&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the core purposes of Node-RED Dashboard has always been to provide low-code access to charting your data. With the 0.7.x releases we&#39;ve made some big improvements to the UI Chart node to make it easier to use and more powerful.&lt;/p&gt;
&lt;p&gt;In Dashboard 1.0, it was common place to have to regularly re-format your own data into &lt;code&gt;{x, y}&lt;/code&gt; structure to be chart-friendly. In &lt;code&gt;0.7.0&lt;/code&gt; we&#39;ve introduced the concept of &lt;strong&gt;key mapping&lt;/strong&gt;, where you can specify which keys in your data object should be used for the x and y axes. This means you can now pass in data in the format you want to use, and the chart will do the rest.&lt;/p&gt;
&lt;p&gt;For example, when rendering a chart of our weekly npm downloads, we have a data structure:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-86&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-86&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;YYYY-MM-DD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;downloads&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;YYYY-MM-DD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;downloads&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;YYYY-MM-DD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;downloads&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-86&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Rather than having to pipe this into a &lt;code&gt;function&lt;/code&gt; node and re-map the properties to &lt;code&gt;{ x, y }&lt;/code&gt;, we can now use the &lt;code&gt;ui-chart&lt;/code&gt;&#39;s key mapping properties:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ui-chart-key-mapping&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-keymap-properties.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Resulting in the following chart:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ui-chart-key-mapping&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-mapping.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;multiple-lines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#multiple-lines&quot;&gt;Multiple Lines&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Note above, another new option has been added to define &lt;em&gt;&amp;quot;Series&amp;quot;&lt;/em&gt;. In Dashboard 1.0 this was fixed as &lt;code&gt;msg.topic&lt;/code&gt; at all times, and defined which line/series data points rendered too. Now, this is configurable, and can even be set as a &lt;code&gt;key:&lt;/code&gt; type too, whereby each data point being treated individually, and grouped based on a given key/property.&lt;/p&gt;
&lt;p&gt;Another great new feature here is the type &lt;code&gt;JSON&lt;/code&gt; for this property. We can provide a &lt;em&gt;list&lt;/em&gt; of series labels, and the chart will render each value from a single data point as separate lines.&lt;/p&gt;
&lt;p&gt;For example, if we consider the data:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-111&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-111&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-10-23&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;humidity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-10-24&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;humidity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-10-25&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;27&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;humidity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-111&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We can provide a series: &lt;code&gt;[&amp;quot;temperature&amp;quot;, &amp;quot;humidity&amp;quot;]&lt;/code&gt; like so:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ui-chart-key-mapping&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-series-property.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Which would result in the following plot:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ui-chart-key-mapping&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ui-chart-multipoint.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We appreciate this offers a new way of working with data in Dashboard, but hopefully, once you&#39;ve tried it, you&#39;ll find it much easier to work with, and see the value it brings when working with your own data sets.&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new-in-0.7.x%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#what-else-is-new-in-0.7.x%3F&quot;&gt;What else is new in 0.7.x?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst we focussed this article on the migration paths and new UI Chart features, we did also squeeze quite a lot more into the 0.7.x releases too with plenty other fixes and improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/279&quot;&gt;Re-architecture of Server-side State Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/327&quot;&gt;Y Axis Min/Max Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/320&quot;&gt;&amp;quot;Focus&amp;quot; button for widgets added to Sidebar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/310&quot;&gt;No more &amp;quot;blue screen&amp;quot; and improved error reporting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/pull/301&quot;&gt;Better route handling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also read the more comprehensive release notes for each release here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.7.0&quot;&gt;0.7.0 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.7.1&quot;&gt;0.7.1 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.7.2&quot;&gt;0.7.2 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;follow-our-progress&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/dashboard-0-7/#follow-our-progress&quot;&gt;Follow our Progress&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As always, thanks for reading and your interested in Dashboard 2.0. If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/community-news-11/</id>
        <title>Community News November 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-11-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/community-news-11/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for November 2023, a monthly roundup of what’s been happening with FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-team-summit---barcelona-by-grey&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#flowfuse-team-summit---barcelona-by-grey&quot;&gt;FlowFuse Team Summit - Barcelona by Grey&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first week of November in Barcelona, the FlowFuse team embraced a blend of culture, collaboration, and creativity at our biannual summit. As a global remote-first company, these gatherings are key to nurturing the camaraderie and clear communication that fuels our work.&lt;/p&gt;
&lt;p&gt;My first summit was a vibrant tableau of wit and good-natured sarcasm, a perfect fit for my sense of humor. But it wasn&#39;t just about the fun; we delved deep into aligning our strategies to streamline communication with the vast community that recognizes the value of Node-RED.&lt;/p&gt;
&lt;p&gt;From segway tours through historic streets to culinary competitions, we bonded and built memories. During the day, we crafted go-to-market strategies, fortified our team dynamics through board games, and honed our sales approaches. The latest dashboard visualizations and product roadmaps were discussed, with our shared vision to simplify the complex for companies worldwide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“The easy things should be easy, and the hard things should be possible.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our goal remains steadfast: to enhance bidirectional communication with you, our valued community, and make Node-RED&#39;s power more accessible than ever.&lt;/p&gt;
&lt;img src=&quot;https://flowfuse.com/blog/2023/11/images/IMG_6334.jpg&quot; width=&quot;500&quot; /&gt;
&lt;h2 id=&quot;announcements-tldr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#announcements-tldr&quot;&gt;Announcements TLDR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re excited to share some significant enhancements that will elevate your experience with FlowFuse and Node-RED. We&#39;ve announced that Dashboards 2.0 are in Beta version.  Recent additions to Dashboards 2.0 include integrating Vuetify and Mermaid into Dashboard 2.0 unlocking a suite of custom UI components to enrich your dashboards. Our step-by-step guide will walk you through creating dynamic elements like countdown timers, leveraging the power of VueJS for seamless updates.&lt;/p&gt;
&lt;p&gt;We&#39;re also thrilled to introduce FlowFuse Blueprints - a game-changer in building bespoke, flexible, and resilient manufacturing applications. Our initial set of Blueprints, including ANDON Operator Terminal, Performance Overview Dashboard, and OEE Calculator, provide preconfigured Node-RED applications that streamline your development process. Dive into the world of Blueprints and discover how they can accelerate your project&#39;s journey from concept to operational reality.  Join the &lt;a href=&quot;https://flowfuse.com/webinars/2023/blueprints/&quot;&gt;webinar&lt;/a&gt; to find out more.&lt;/p&gt;
&lt;h2 id=&quot;recent-changelog-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#recent-changelog-updates&quot;&gt;Recent Changelog Updates&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/&quot;&gt;Integrate your own widgets with Dashboard 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/10/blueprints/&quot;&gt;Blueprints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/10/device-snapshot-selection/&quot;&gt;Enhanced Snapshot Selection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/10/path-bug-fix/&quot;&gt;Device Agent path bug fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/10/resource-alerts/&quot;&gt;Resource Monitoring in Audit Log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/10/certified-nodes/&quot;&gt;Certified Nodes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse-blueprints%3A-your-pathway-to-enhanced-manufacturing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#flowfuse-blueprints%3A-your-pathway-to-enhanced-manufacturing&quot;&gt;FlowFuse Blueprints: Your Pathway to Enhanced Manufacturing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Explore building manufacturing applications with FlowFuse Blueprints in our upcoming webinar. Blueprints make it easy to get started building applications with Node-RED.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/blueprints/&quot;&gt;Sign-up today&lt;/a&gt; to join us on November 30th.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/11/meet-us-at-sps-nuremberg/&quot;&gt;Meet FlowFuse at SPS Nuremberg&lt;/a&gt; - Talk about Node-RED and how FlowFuse can help you operationalize your flows!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/hardware/raspberry-pi-5/&quot;&gt;Install the FlowFuse Edge Agent on the Raspberry Pi 5&lt;/a&gt; - Managing your Raspberry Pi 5 with Node-RED through FlowFuse is easy to set up&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/&quot;&gt;Innovate from within - Why manufacturing must embrace Citizen Developers&lt;/a&gt; - Empower your Operational Technology teams as Citizen Developers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/&quot;&gt;Embracing Innovation: Build vs Buy in MES&lt;/a&gt; - Bridging the Gap: Uniting MES Development with Automation System Practices&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/blueprints/&quot;&gt;What are FlowFuse Blueprints?&lt;/a&gt; - Preconfigured Node-RED Applications&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/&quot;&gt;Integrate your own widgets with Dashboard 2.0&lt;/a&gt; - With the 0.6.0 Release of Dashboard 2.0, we now support third-party widget integration. Read more in this deep dive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/blueprints/&quot;&gt;What are FlowFuse Blueprints?&lt;/a&gt; - Preconfigured Node-RED Applications&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/community-news-11/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/11/meet-us-at-sps-nuremberg/</id>
        <title>Meet FlowFuse at SPS Nuremberg</title>
        <summary>Talk about Node-RED and how FlowFuse can help you operationalize your flows!</summary>
        <updated>2023-11-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/11/meet-us-at-sps-nuremberg/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;FlowFuse is excited to be exhibiting at the SPS in Nuremberg next week. We will
be located in Hall 5 Booth 145.&lt;/p&gt;
&lt;p&gt;At the SPS, we will be showcasing our latest FlowFuse platform, which is a
powerful and user-friendly tool for creating and managing Node-RED flows. There&#39;s
also an option to get a demonstration of how FlowFuse can be used to solve a
variety of industrial automation problems.&lt;/p&gt;
&lt;p&gt;We are also keen to meet with Node-RED users and FlowFuse prospective customers
at the SPS. If you would like to book a meeting with us, please visit our
&lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact us&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;We look forward to seeing you at the SPS!&lt;/p&gt;
&lt;h3 id=&quot;about-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/meet-us-at-sps-nuremberg/#about-flowfuse&quot;&gt;About FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse is a software company that develops tools for creating and managing
Node-RED flows. Node-RED is a popular open-source platform for flow-based programming. FlowFuse makes it easy to create and manage complex Node-RED flows, even for users with no prior programming experience.&lt;/p&gt;
&lt;p&gt;FlowFuse is used by a wide range of organizations, including manufacturers, utilities, and research institutions. FlowFuse is used to solve a variety of industrial automation problems, such as data acquisition, data enrichment,
and process monitoring.&lt;/p&gt;
&lt;h3 id=&quot;about-sps-nuremberg&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/11/meet-us-at-sps-nuremberg/#about-sps-nuremberg&quot;&gt;About SPS Nuremberg&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;SPS Nuremberg is the world&#39;s leading trade fair for electric automation. The fair takes place annually in Nuremberg, Germany. SPS Nuremberg is a showcase for the latest innovations in industrial automation.&lt;/p&gt;
&lt;p&gt;We hope to see you at the SPS!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/citizen-development/</id>
        <title>Innovate from within - Why manufacturing must embrace Citizen Developers</title>
        <summary>Empower your Operational Technology teams as Citizen Developers</summary>
        <updated>2023-10-30T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/citizen-development/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;In the early days when I was working as a solution architect, I found myself in a peculiar position, observing an intriguing relationship between Operational Technology (OT) and Information Technology (IT) departments. While OT departments struggled to develop digital solutions, the IT departments held an unspoken authority in this domain, leading to a paradoxical dynamic that often seemed to hinder rather than facilitate progress.&lt;/p&gt;
&lt;p&gt;As a solution architect working within this environment, I found myself uniquely positioned to bridge the gap between these two groups while also helping them find common ground on which they could build successful projects together. To do so effectively, I needed to understand each group&#39;s perspective and determine how best they could collaborate without compromising either side&#39;s autonomy or objectives. This task was not always easy but ultimately proved rewarding once achieved successfully.&lt;/p&gt;
&lt;h2 id=&quot;a-tale-of-shadow-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/#a-tale-of-shadow-it&quot;&gt;A Tale of Shadow IT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the best-case scenarios, IT departments considered themselves as vendors, and OT, the customers. However, the IT-driven, off-the-shelf solutions seldom proved to be the right fit for the problems at hand. This mismatch often led to the birth of shadow IT systems—solutions that were not sanctioned by IT, yet were deemed necessary to maintain operational efficiency.
In this realm of shadow IT, I&#39;ve observed countless solutions running on desktop PCs, hidden from the eyes of IT departments, solving problems in manufacturing quickly—a situation born of necessity, with which no one could be satisfied. I cannot deny that Node-RED, an open-source low-code programming tool, has very often been one of these shadow IT systems, enabling data modification, lightweight HMI creation, and empowering the OT workforce.&lt;/p&gt;
&lt;p&gt;However, this under-the-radar approach is fraught with dangers. With unprotected systems and without official oversight, the potential for security breaches is a real and present danger. I would wager that even today, a simple scan on port 1880 would reveal a multitude of open Node-RED environments. This double-edged sword of innovation and insecurity highlights the urgent need for a paradigm shift.&lt;/p&gt;
&lt;h2 id=&quot;why-are-citizen-developers-important-in-manufacturing%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/#why-are-citizen-developers-important-in-manufacturing%3F&quot;&gt;Why are Citizen Developers Important in Manufacturing?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Citizen developers are individuals who create applications and software solutions for their organizations without any background in computer programming. These citizen developers leverage low-code platforms to build apps that automate tasks, streamline processes, and improve existing systems&#39; user experiences. Citizen developers are a growing trend in the industry, serving as a key factor in harmonizing IT and OT interests. They bring an array of benefits that can make businesses more efficient and cost-effective. From reducing development costs to increasing productivity, citizen developers offer significant value to organizations seeking ways to stay competitive.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Acceleration of Software Development:&lt;/strong&gt; Low-code platforms significantly expedite the software development process, enabling more efficient realization of business requirements. By quickening development, these platforms free up time and resources for design and innovation, leading to higher-quality software that better serves the business&#39;s needs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crafting Bespoke Applications:&lt;/strong&gt; By empowering non-professional coders with the right tools and resources, organizations can democratize digital solutions. This not only facilitates the creation of custom systems that fit seamlessly into existing infrastructures but also enables rapid ideation and development, even for those without prior coding experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhancement of Operational Processes and Customer Experiences:&lt;/strong&gt; With the automation capabilities of low-code platforms and the innovative solutions generated by citizen developers, operational processes can be optimized, and customer experiences significantly improved. The synergy between these elements can lead to efficiency gains through automation and the delivery of more effective, customer-centric solutions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This shift toward embracing citizen development within manufacturing represents a unique opportunity where both sides benefit significantly; not only do OT departments gain access to custom applications tailored precisely for their needs, but IT teams can lead guidance for self-empowerment, resulting in greater efficiency through automation.&lt;/p&gt;
&lt;h2 id=&quot;democratize-application-development-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/#democratize-application-development-with-node-red&quot;&gt;Democratize Application Development with Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the past decade, Node-RED has been a pioneer in low-code tools, democratizing application development in manufacturing. It provides powerful data collection, transformation, and visualization capabilities, simplifying the application-building process.
As an open-source tool with no associated costs or licensing fees, Node-RED is &lt;a href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#the-standard-for-edge-computing-and-plcs&quot;&gt;increasingly popular&lt;/a&gt; among manufacturers seeking to quickly develop custom applications without extensive coding knowledge or experience.
FlowFuse takes things one step further, offering organizations a way to officially incorporate and scale Node-RED, making it compliant, governed, and secure within the existing solution landscape.&lt;/p&gt;
&lt;h2 id=&quot;the-strategic-imperative-of-citizen-development&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/citizen-development/#the-strategic-imperative-of-citizen-development&quot;&gt;The Strategic Imperative of Citizen Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For industry decision-makers, this is a call to action. It is imperative to nurture this growing community within your workforce, providing them with the tools, platforms, and, importantly, the organizational support they require. The empowerment of citizen developers could very well be the deciding factor in your organization&#39;s ability to stay competitive, agile, and innovative in a rapidly evolving market.&lt;/p&gt;
&lt;p&gt;Looking to the future, the success of modern manufacturing lies in its people and their ability to solve problems with the right tools at their fingertips. Citizen development has the potential to  break down the barriers. Organizations that recognize and invest in this potential will undoubtedly lead the charge.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/certified-nodes/</id>
        <title>What are Certified Nodes?</title>
        <summary>Enhanced Security, Quality, and Support</summary>
        <updated>2023-10-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/certified-nodes/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;We are thrilled to introduce a new feature for our Teams and Enterprise Tier customers - &lt;strong&gt;Certified Nodes for Node-RED&lt;/strong&gt;. This new offering is designed to reinforce your flows&#39;s robustness by granting you access to Node-RED nodes that stand up to our rigorous quality and security standards.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-certified-node%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/#what-is-a-certified-node%3F&quot;&gt;What is a certified node?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A certified node is a module from the Node-RED library that undergoes a certification process, ensuring it adheres to standards that address three core pillars:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quality&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Testing phases for each node.&lt;/li&gt;
&lt;li&gt;Operational reliability and compatibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proactive resolution of potential vulnerabilities.&lt;/li&gt;
&lt;li&gt;Revocation of certification for nodes falling short on security, with prompt notifications to affected customers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Support&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ambitious aim towards effective issue resolution.&lt;/li&gt;
&lt;li&gt;Assistance for troubleshooting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-use-certfied-nodes%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/#how-to-use-certfied-nodes%3F&quot;&gt;How to use certfied nodes?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Accessing certified nodes is straightforward—they&#39;re integrated directly within your Node-RED palette manager, simplifying selection and implementation. All new instances since October 26, 2023, have automatic access to the catalogue. If you want to add Certified Nodes to one of your existing instances, just &lt;a href=&quot;https://flowfuse.com/support/&quot;&gt;contact us&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Node-RED palette manager&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/certified-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-kind-of-nodes-are-included%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/#what-kind-of-nodes-are-included%3F&quot;&gt;What kind of Nodes are included?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our initial roll-out includes a curated assortment of certified nodes. We&#39;re continuously expanding our library, with upcoming weeks bringing a wider array of options. Should you find a gap in your desired functionalities, we encourage you to &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24/&quot;&gt;reach out&lt;/a&gt;. Your feedback drives our journey forward, influencing the nodes we introduce next.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linting for Node-RED&lt;/li&gt;
&lt;li&gt;Enhanced debugging for Node-RED&lt;/li&gt;
&lt;li&gt;FlowFuse Snapshot Plugin&lt;/li&gt;
&lt;li&gt;Node-RED Dashboard 2.0&lt;/li&gt;
&lt;li&gt;E-Mail Communication&lt;/li&gt;
&lt;li&gt;Base64 converter&lt;/li&gt;
&lt;li&gt;Buffer Parser&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;InfluxDB&lt;/li&gt;
&lt;li&gt;Omron PLC&lt;/li&gt;
&lt;li&gt;MC Protocol (Mitsubishi PLCs)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-will-follow-in-the-coming-weeks%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/certified-nodes/#what-will-follow-in-the-coming-weeks%3F&quot;&gt;What will follow in the coming weeks?&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Siemens PLC&lt;/li&gt;
&lt;li&gt;Modbus&lt;/li&gt;
&lt;li&gt;Mssql&lt;/li&gt;
&lt;li&gt;Rockwell and Allen Bradley&lt;/li&gt;
&lt;li&gt;OPC-UA&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;WhatsAPP, Telegram, Slack&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/mes-build-buy/</id>
        <title>Embracing Innovation: Build vs Buy in MES</title>
        <summary>Bridging the Gap: Uniting MES Development with Automation System Practices</summary>
        <updated>2023-10-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/mes-build-buy/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Manufacturing companies often struggle to choose between building custom MES solutions or buying ready-made software. Both options have their strengths, but they can fall short of providing the flexibility and control engineers need. A hybrid approach—combining the best of both worlds—is changing the game. In this article, we’ll explore how Node-RED and FlowFuse make it easier to create MES systems that are efficient, adaptable, and perfectly suited to your needs.&lt;/p&gt;
&lt;h2 id=&quot;the-hybrid-approach%3A-a-best-of-both-worlds-strategy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#the-hybrid-approach%3A-a-best-of-both-worlds-strategy&quot;&gt;The Hybrid Approach: A Best of Both Worlds Strategy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Much like the practice of outsourcing machine installation while specifying detailed requirements, a hybrid approach to MES systems leverages the expertise of SI companies while retaining control over critical aspects of system design. This approach recognizes that automation engineers possess valuable insights into the unique needs of their manufacturing processes. They can specify crucial details such as wire coloring schemes, downtime conventions, Andon board standards, PLC types, and even the code used on PLCs.&lt;/p&gt;
&lt;h2 id=&quot;node-red%3A-the-mes-code&#39;s-best-friend&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#node-red%3A-the-mes-code&#39;s-best-friend&quot;&gt;Node-RED: The MES Code&#39;s Best Friend&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED emerges as a game-changer in this paradigm. It is an open-source, flow-based development tool renowned for its ability to connect everything, from PLCs to relational databases to firewalls, empowering engineers to create MES system logic visually. Node-RED simplifies the process by enabling engineers to drag and drop nodes and wires to define the logic flow. This visual approach not only streamlines development but also enhances the transparency of the codebase.&lt;/p&gt;
&lt;h2 id=&quot;the-power-of-standardization-and-code-clarity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#the-power-of-standardization-and-code-clarity&quot;&gt;The Power of Standardization and Code Clarity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the primary reasons behind Node-RED&#39;s appeal is its ability to standardize code. Just as Ladder Logic and Function Block Diagrams have long been favored for their clarity, Node-RED fosters a coding environment where engineers can easily understand and build upon each other&#39;s work. This standardization ensures that MES systems remain in sync with the rest of the plant, making troubleshooting and maintenance more efficient.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse%3A-bridging-the-gap-to-deployment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#flowfuse%3A-bridging-the-gap-to-deployment&quot;&gt;FlowFuse: Bridging the Gap to Deployment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When it comes to deploying MES systems, FlowFuse enters the scene as a vital companion to Node-RED. FlowFuse is a deployment platform that seamlessly integrates with Node-RED, allowing for effortless deployment of applications to a customer&#39;s environment. Its user-friendly interface makes it easy for automation engineers to manage and scale their MES systems.&lt;/p&gt;
&lt;h2 id=&quot;pioneering-the-future%3A-the-strategic-adoption-of-node-red-and-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#pioneering-the-future%3A-the-strategic-adoption-of-node-red-and-flowfuse&quot;&gt;Pioneering the Future: The Strategic Adoption of Node-RED and FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Embracing Node-RED and FlowFuse in MES system development is not just a technical choice; it&#39;s a strategic one. By adopting this hybrid approach, manufacturing companies position themselves as thought leaders in the industry. They demonstrate a commitment to innovation, transparency, and adaptability.&lt;/p&gt;
&lt;h2 id=&quot;elevate-your-mes-strategy%3A-embrace-node-red-and-flowfuse-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/mes-build-buy/#elevate-your-mes-strategy%3A-embrace-node-red-and-flowfuse-today&quot;&gt;Elevate Your MES Strategy: Embrace Node-RED and FlowFuse Today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, the answer to the build vs. buy dilemma for MES systems is not one or the other—it&#39;s both. Node-RED and FlowFuse offer a dynamic partnership that empowers manufacturing companies to craft MES solutions that are tailored to their needs while harnessing the expertise of System Integration companies. The call to action is clear: Embrace Node-RED and FlowFuse as the catalysts for your manufacturing innovation journey.&lt;/p&gt;
&lt;p&gt;For more information about FlowFuse and how it can revolutionize your MES system deployment, visit FlowFuse.com Start building MES systems that are not just efficient but also future-ready, and become a trailblazer in the world of industrial manufacturing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/</id>
        <title>Service Disruption Report for October 11th, 2023</title>
        <summary></summary>
        <updated>2023-10-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;On October 11th, 2023, we had an issue where users were not able to access the
Node-RED editor, recieving a &#39;Access Denied&#39; error message.
This post examines the issue that was hit, the timeline of events and
what we&#39;ve done to resolve it.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As part of our company rebranding, we planned a migration for our FlowFuse Cloud
platform from &lt;code&gt;app.flowforge.com&lt;/code&gt; to &lt;code&gt;app.flowfuse.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We applied this change in co-ordination with our customers using Single Sign On
as it required an update to their configuration to match.&lt;/p&gt;
&lt;p&gt;This was done on Tuesday October 10th and all confirmed working with those customers.&lt;/p&gt;
&lt;p&gt;On Wednesday October 11th we received two reports that separate users could not
access their Node-RED editors. We quickly identified the issue was related to
how the Node-RED editors authenticated users against the platform for non-SSO users.&lt;/p&gt;
&lt;p&gt;A workaround was identified to ensure users were logged in via the new domain.&lt;/p&gt;
&lt;p&gt;We then looked at options to mitigate this for other users. We could not roll
back the domain name migration as it would have required co-ordinated action with
multiple SSO customers - who were not otherwise impacted by this issue.&lt;/p&gt;
&lt;h2 id=&quot;resolution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/#resolution&quot;&gt;Resolution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We tested various approaches of adding automatic redirection from one domain to
the other. Due to the fact all existing Instances and Devices had the old domain
name hardcoded into their settings, we were limited in what we could do here.&lt;/p&gt;
&lt;p&gt;We ultimately applied a single redirect for &lt;code&gt;https://app.flowforge.com&lt;/code&gt; to
&lt;code&gt;https://app.flowfuse.com&lt;/code&gt; - without any redirecting of paths beneath either domain.&lt;/p&gt;
&lt;p&gt;This URL is only accessed by real users when coming to log into the platform. By
redirecting at that point in time, it ensures they are logged into the new domain
and everything works as expected.&lt;/p&gt;
&lt;p&gt;For users with active sessions on the old domain, a simple log out and log back in
will get them on to the new domain.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Having resolved the immediate issue we looked at how this situation came to happen
and why it wasn&#39;t caught in our preparation for the migration.&lt;/p&gt;
&lt;p&gt;We have a staging environment where we verify any changes before they get applied
to production. We all have SSO enabled in that environment and a small number of
test users without SSO enabled.&lt;/p&gt;
&lt;p&gt;Our testing had focused on the SSO users which, by virtue of the SSO process, ensured
they ended up logged into the new domain.&lt;/p&gt;
&lt;p&gt;The testing done with non-SSO users was more limited and didn&#39;t hit the right combination
of having existing log sessions on one or other of the domains to match the scenario
hit by our customers.&lt;/p&gt;
&lt;p&gt;We also identified some items to follow up on around how the existing Instances
and Devices handle HTTP redirects. Currently, the Device Agent is not configured
to follow redirects. That is a change we have &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/182&quot;&gt;added to the backlog&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;timeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/service-disruption-report-2023-10-11/#timeline&quot;&gt;Timeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;All times are BST.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tuesday October 10th&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We updated the platform&#39;s primary domain name to &lt;code&gt;app.flowfuse.com&lt;/code&gt; whilst keeping &lt;code&gt;app.flowforge.com&lt;/code&gt; active. This was done in co-ordination with our SSO customers who needed to make an update to their SSO configuration at the same time. Both customers reported success following the change.&lt;/p&gt;
&lt;p&gt;Our own validation demonstrated we could login via our own SSO, access editors, and devices continued to work as before (in particular, device editor and snapshot gathering).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wednesday October 11th&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;11:50&lt;/strong&gt; and &lt;strong&gt;11:57&lt;/strong&gt; - we received two support request from a user getting an &#39;access denied&#39; error when trying to access an editor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;12:09&lt;/strong&gt; - Workaround shared with both customers to login via the new domain first&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;12:30&lt;/strong&gt; - We applied a blanket redirect for &lt;code&gt;app.flowforge.com&lt;/code&gt; to &lt;code&gt;app.flowfuse.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;12:50&lt;/strong&gt; - We then reduced the scope of the redirect so that devices would not be impacted&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;13:14&lt;/strong&gt; - A secondary issue with logging into the editor when logged in on the new domain was reported internally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;13:44&lt;/strong&gt; - Reverted all of the redirect handling whilst reviewing the problems with the previous redirects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;14:20&lt;/strong&gt; - We applied a redirect to just the root of the domain and documented for our support channel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No further reports were received after this time.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/blueprints/</id>
        <title>What are FlowFuse Blueprints?</title>
        <summary>Preconfigured Node-RED Applications</summary>
        <updated>2023-10-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/blueprints/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Starting today, FlowFuse Blueprints are available on FlowFuse Cloud. Additionally, upon request, all our Teams and Enterprise Self-Hosted customers gain access to this collection. But what exactly are FlowFuse Blueprints?&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-blueprints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#flowfuse-blueprints&quot;&gt;FlowFuse Blueprints&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Blueprints aim to make the Node-RED experience more accessible for newcomers, while also offering a treasure trove of fresh ideas for seasoned Node-RED users. When setting up a new Node-RED instance, you now have the option to choose a blueprint tailored for specific use cases. For example, our &amp;quot;ANDON Operator Terminal&amp;quot; blueprint can be selected, and it will automatically configure the Node-RED instance, sparing you the need to start from scratch. While these templates are powerful out-of-the-box, they&#39;re also fully customizable, allowing you to tweak them to suit your unique requirements. Ultimately, blueprints speed up the learning curve for new users and expedite the solution-building process for experienced ones.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-blueprints%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#how-to-use-blueprints%3F&quot;&gt;How to use Blueprints?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All our FlowFuse Cloud users can select a Blueprint directly while creating a new Node-RED instance. Self-hosted customers can request access to our blueprints via a &lt;a href=&quot;https://flowfuse.com/support/&quot;&gt;support ticket&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-first-three-blueprints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#the-first-three-blueprints&quot;&gt;The first three Blueprints&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the coming weeks, we&#39;ll be releasing a multitude of blueprints tailored for diverse use cases. However, we decided to start with with three foundational manufacturing applications designed with the &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;andon-operator-terminal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#andon-operator-terminal&quot;&gt;ANDON Operator Terminal&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Andon Operator Terminal is designed to be at the start of an Andon process, allowing end-users to report any issues with the cell to a supervisor.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ANDON Blueprint Screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ANDON1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;performance-overview-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#performance-overview-dashboard&quot;&gt;Performance Overview Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Performance Overview Dashboard Blueprint provides a real-time snapshot of key performance metrics, delivering a comprehensive overview of manufacturing operations for a specific station or entire line.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Performance Overview Screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/performance-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;oee-calculator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/blueprints/#oee-calculator&quot;&gt;OEE Calculator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If automatic calculations are not feasible, the OEE Calculator Blueprint enables end-users to manually input production data to compute the Overall Equipment Effectiveness (OEE) for a given machine.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;OEE Calculator Screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-data.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/dashboard-integrations/</id>
        <title>Integrate your own widgets with Dashboard 2.0</title>
        <summary>With the 0.6.0 Release of Dashboard 2.0, we now support third-party widget integration. Read more in this deep dive.</summary>
        <updated>2023-10-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/dashboard-integrations/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;With a new release, comes new features for Dashboard 2.0, and the focus of this release has been on improving the developer experience for those building third-party widgets for Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;Dashboard 1.0 had a hugely popular ecosystem of third party widgets (e.g. &lt;code&gt;ui-worldmap&lt;/code&gt;, &lt;code&gt;ui-svg&lt;/code&gt;) and something we&#39;ve been keen to support is a platform where these widgets (and more) can be built and used within Dashboard 2.0 too.&lt;/p&gt;
&lt;p&gt;Whilst we can&#39;t support the existing Dashboard 1.0 extensions directly (given that we&#39;re now VueJS-based, rather than AngularJS), we hope that the framework, documentation and this article, will help springboard the community to build new (and transfer over old) widgets for Dashboard 2.0.&lt;/p&gt;
&lt;h2 id=&quot;building-from-ui-template&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/#building-from-ui-template&quot;&gt;Building from &lt;code&gt;ui-template&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As with Dashboard 1.0, we&#39;ve utilised the flexibility of our &lt;code&gt;ui-template&lt;/code&gt; node here to enable third-party integrations.&lt;/p&gt;
&lt;p&gt;If you&#39;re used the new &lt;code&gt;ui-template&lt;/code&gt; in Dashboard 2.0 already, you&#39;ll know that you can provide raw Vue (HTML) content and it&#39;ll render that into your Dashboard. In 0.6.0, we&#39;ve added &lt;em&gt;a lot&lt;/em&gt; of new functionality to the guts of &lt;code&gt;ui-template&lt;/code&gt;, which we can then extend with our third-party widgets.&lt;/p&gt;
&lt;p&gt;This new functionality includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom Dependencies&lt;/strong&gt; - Injection of external widget dependencies (e.g. other JavaScript libraries) via &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On Input&lt;/strong&gt; - &lt;code&gt;onInput&lt;/code&gt; defines behaviour of the widget in Dashboard when it receives a message in Node-RED.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On Load&lt;/strong&gt; - &lt;code&gt;onMounted&lt;/code&gt; defines functionality when a widget first loads in Dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Functions&lt;/strong&gt; - Define general functions that can be called from within your widget at any point of your choosing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extend Built-In Events&lt;/strong&gt; - Our built in &lt;code&gt;send&lt;/code&gt; function can be called within your widget&#39;s template, and will send a message back to Node-RED, with any content of your choosing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom SocketIO Event Handlers&lt;/strong&gt; - If you want to extend the communication between Dashboard and Node-RED, you can emit your own SocketIO events from Dashboard, and have respective handlers for those events in Node-RED.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also have plans to expose more of this new functionality to the &lt;code&gt;ui-template&lt;/code&gt; interface itself within Node-RED, but for now it&#39;s mostly available when developing third-party widgets.&lt;/p&gt;
&lt;h2 id=&quot;useful-resources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/#useful-resources&quot;&gt;Useful Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re interested in building integrations, then we&#39;ve also built a couple of resources to help you get started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/contributing/widgets/third-party.html&quot;&gt;Widget Development Guide&lt;/a&gt; - A guide for how to structure your own widgets, and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard-example-node&quot;&gt;Example Integration (Repo)&lt;/a&gt; - We&#39;ve open sourced a very simple &lt;code&gt;ui-example&lt;/code&gt; node that demonstrates how you can build your own widget for Dashboard 2.0, that utilises all of the features highlighted above.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-else-is-new-in-0.6.0%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/dashboard-integrations/#what-else-is-new-in-0.6.0%3F&quot;&gt;What else is new in 0.6.0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whilst we focussed this article on the third-party integrations, we did also squeeze quite a lot more into the 0.6.0 release too with plenty &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.6.0&quot;&gt;other fixes and improvements&lt;/a&gt;, including the separation of the Dash oard 2.0 nodes into a new &amp;quot;Dashboard 2&amp;quot; category in the Node-RED palette.&lt;/p&gt;
&lt;p&gt;As always, thanks for reading and your interested in Dashboard 2.0. If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/community-news-10/</id>
        <title>Community News October 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-10-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/community-news-10/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for October 2023, a monthly roundup of what’s been happening with FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;quicker-releases-for-flowfuse-cloud-and-new-changelog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#quicker-releases-for-flowfuse-cloud-and-new-changelog&quot;&gt;Quicker Releases for FlowFuse Cloud and New Changelog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is committed to delivery new features to our customers and community as fast as possible. We are now rolling out new builds of FlowFuse to FlowFuse Cloud more regularly than the previous monthly release. This will allow FlowFuse Cloud users to benefit from the latest enhancements as they become available. The self-hosted version of FlowFuse will continue to have releases every 4 weeks.&lt;/p&gt;
&lt;p&gt;To allow FlowFuse Cloud users to keep up to date on the new changes, we have started a &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Changelog&lt;/a&gt; to announce newly deployed features.&lt;/p&gt;
&lt;h2 id=&quot;recent-changelog-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#recent-changelog-updates&quot;&gt;Recent Changelog Updates&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/09/devops-actions/&quot;&gt;DevOps Pipeline with action selection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/09/snapshots-devices/&quot;&gt;Usability improvements to Device Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/09/introduction-enterprise-tier/&quot;&gt;Introducing the Enterprise tier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/changelog/2023/09/pipeline-api/&quot;&gt;API Endpoints for DevOps Pipeline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/&quot;&gt;Private Node Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;dashboard-2.0---where-we-are%2C-and-what%E2%80%99s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#dashboard-2.0---where-we-are%2C-and-what%E2%80%99s-next%3F&quot;&gt;Dashboard 2.0 - Where we are, and what’s next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next generation of the Node-RED dashboard is starting to mature. Development work on Dashboard 2.0 started earlier this year and amazing progress has been made already. Join Joe Pavitt, leader of the Dashboard 2.0 project, who will demonstrate the new dashboard project and discuss future plans during our October webinar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/dashboard-20/&quot;&gt;Sign-up today&lt;/a&gt; to join us on October 26.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/&quot;&gt;Custom Vuetify components for Dashboard 2.0&lt;/a&gt; - the new dashboard project allows for custom UI components&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/rebranding-our-components/&quot;&gt;Updating our branding across GitHub, npm and Dockerhub&lt;/a&gt; - our GitHub, npm and DockerHub locations are now called FlowFuse, due to the rename from FlowForge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/&quot;&gt;How ChatGPT improves Node-RED Developer Experience&lt;/a&gt; - lots of interest in ChapGPT in the Node-RED community. A quick review of different integrations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/&quot;&gt;Share &amp;amp; Preview Flows on flows.nodered.org&lt;/a&gt; - A new way to visualize flows in web pages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/integration-technologies/rest/&quot;&gt;Charting REST API Data in a Dashboard&lt;/a&gt; - A short tutorial on how to gather data from a REST API for a dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modernize your legacy industrial data - Two part series on making sense of your industrial data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/&quot;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/&quot;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/community-news-10/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/</id>
        <title>How to Use Private Custom Nodes in FlowFuse?</title>
        <summary>Run your own private Node-RED catalogue and npm repository for custom nodes</summary>
        <updated>2023-10-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/"/>
        <author><name></name></author>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;With version 1.12 of FlowFuse, it is now possible to use your custom nodes. In this article, we&#39;ll explain how to do that.&lt;/p&gt;
&lt;div class=&quot;blog-update-notes&quot;&gt;
    &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; Since this article was published, we&#39;ve made this even easier on FlowFuse!&lt;/p&gt;
    &lt;p&gt;Now, FlowFuse includes a private registry for all Team and Enterprise Tier customers, so there is no need to host and manage your own.&lt;/p&gt;
    &lt;p&gt;You can view our documentation on this feature &lt;a href=&quot;https://flowfuse.com/docs/user/custom-npm-packages/&quot;&gt;here&lt;/a&gt;&lt;/p&gt; 
&lt;/div&gt;
&lt;p&gt;What do we mean by custom nodes? Typically, Node-RED nodes are hosted publicly on the npmjs registry, making them accessible to everyone for download and contribution. However, there are use cases where you may not want to share your developed nodes publicly. In such scenarios, it becomes necessary to run your own private Node-RED catalog and npm repository. This approach allows you to manage your custom nodes securely and efficiently.&lt;/p&gt;
&lt;h2 id=&quot;step-1---setting-up-a-private-npm-repository&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#step-1---setting-up-a-private-npm-repository&quot;&gt;Step 1 - Setting Up a Private npm Repository&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you can use custom nodes, you&#39;ll need a place to store them.&lt;/p&gt;
&lt;h3 id=&quot;option-1---service-provider&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#option-1---service-provider&quot;&gt;Option 1 - Service Provider&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Choose a public service provider, like &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npmjs&lt;/a&gt;, that allows you to host private packages and upload your node module.&lt;/p&gt;
&lt;h3 id=&quot;option-2---verdaccio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#option-2---verdaccio&quot;&gt;Option 2 - Verdaccio&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another option is to use Verdaccio, a lightweight private npm proxy registry that allows you to run your own registry.&lt;/p&gt;
&lt;h4 id=&quot;installing-verdaccio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#installing-verdaccio&quot;&gt;Installing Verdaccio&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Install Verdaccio using npm:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-35&quot;&gt;
  &lt;pre class=&quot;language-sh&quot;&gt;&lt;code id=&quot;code-35&quot; class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; verdaccio&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-35&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Run Verdaccio:&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-43&quot;&gt;
  &lt;pre class=&quot;language-sh&quot;&gt;&lt;code id=&quot;code-43&quot; class=&quot;language-sh&quot;&gt;verdaccio&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-43&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will start Verdaccio on &lt;code&gt;http://localhost:4873&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&quot;configuring-verdaccio&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#configuring-verdaccio&quot;&gt;Configuring Verdaccio&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The default configuration supports scoped packages and allows any user to access all packages, although only authenticated users can publish.&lt;/p&gt;
&lt;p&gt;If necesarry you can edit the Verdaccio configuration file, usually found at &lt;strong&gt;~/.config/verdaccio/config.yaml&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Refer to the &lt;a href=&quot;https://verdaccio.org/docs/configuration/&quot;&gt;documentation&lt;/a&gt; for all configuration options.&lt;/p&gt;
&lt;p&gt;It is important that if you intend to use a private NPM registry with FlowFuse Cloud, the registry will need to be publicly exposed to the internet. Please make sure you understand how to secure it appropriately.&lt;/p&gt;
&lt;h4 id=&quot;publish-your-package&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#publish-your-package&quot;&gt;Publish your package&lt;/a&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Create a user&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-72&quot;&gt;
  &lt;pre class=&quot;language-sh&quot;&gt;&lt;code id=&quot;code-72&quot; class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; adduser &lt;span class=&quot;token parameter variable&quot;&gt;--registry&lt;/span&gt; http://localhost:4873/&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-72&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Publish you package&lt;/li&gt;
&lt;/ol&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-80&quot;&gt;
  &lt;pre class=&quot;language-sh&quot;&gt;&lt;code id=&quot;code-80&quot; class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; publish &lt;span class=&quot;token parameter variable&quot;&gt;--registry&lt;/span&gt; http://localhost:4873/&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-80&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h2 id=&quot;step-2---creating-your-private-node-red-catalog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#step-2---creating-your-private-node-red-catalog&quot;&gt;Step 2 - Creating Your Private Node-RED Catalog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are several ways to generate your own &lt;code&gt;catalogue.json&lt;/code&gt;, which is necessary for Node-RED to understand which packages are available where. Below, we&#39;ll show you two of the many options to create and host a &lt;code&gt;catalogue.json&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;option-1---web-app&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#option-1---web-app&quot;&gt;Option 1 - Web App&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To create and host a Node-RED catalog, we recommend the package &lt;a href=&quot;https://github.com/hardillb/node-red-private-catalogue-builder&quot;&gt;&lt;code&gt;node-red-private-catalogue-builder&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The container accepts the following environment variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PORT - Which port to listen on (defaults to 3000)&lt;/li&gt;
&lt;li&gt;HOST - Which local IP Address to bind to (defaults to 0.0.0.0)&lt;/li&gt;
&lt;li&gt;REGISTRY - A host and optional port number to connect to the NPM registry (defaults to http:/ registry:4873)&lt;/li&gt;
&lt;li&gt;KEYWORD - The npm keyword to filter on (defaults to Node-RED)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;It presents 2 HTTP endpoints&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/update - a POST to this endpoint will trigger a rebuild of the catalogue&lt;/li&gt;
&lt;li&gt;/catalogue.json - a GET request returns the current catalogue&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;/update&lt;/code&gt; endpoint can be used with the Verdaccio &lt;a href=&quot;https://verdaccio.org/docs/notifications&quot;&gt;notification&lt;/a&gt; events to trigger the catalogue to automatically when nodes are added or updated.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-136&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-136&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; POST&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;application/json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//localhost&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;3000/update&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;name&quot;: &quot;&quot;, &quot;versions&quot;: &quot;&quot;, &quot;dist-tags&quot;: &quot;&quot;}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-136&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;option-2---node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#option-2---node-red&quot;&gt;Option 2 - Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can also use a FlowFuse Node-RED instance and the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-catalogue&quot;&gt;&lt;code&gt;node-red-contrib-catalogue&lt;/code&gt;&lt;/a&gt; package to generate and host your &lt;code&gt;catalogue.json&lt;/code&gt; file.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;100%&quot; src=&quot;https://flows.nodered.org/flow/1f01a92fdbd4172c75fcb88b44e64954/share&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;step-3---flowfuse-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/use-private-custom-nodes-with-flowfuse/#step-3---flowfuse-configuration&quot;&gt;Step 3 - FlowFuse configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next, you&#39;ll need to add all the details to your FlowFuse instance configuration.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the Catalog: Go to your &lt;strong&gt;Instance&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Palette&lt;/strong&gt;. Here, you&#39;ll have the option to add a catalogue.json. You&#39;ll need to provide the URL from which the catalogue.json can be accessed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example: &lt;strong&gt;https://catalogue.nodered.org/catalogue.json&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is import to remember that this URL must be accessible from the browser running the Node-RED editor and when used with FlowFuse (or any other Node-RED editor accessed via HTTPS) it must be served with HTTPS.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Modify the npmrc File: You&#39;ll need to configure where to find the packages from the catalog, possibly specifying a scope.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Set a new registry for a scoped package
@myscope:registry=https://mycustomregistry.example.org
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If necessary, set authentication-related configurations. See the &lt;a href=&quot;https://docs.npmjs.com/cli/v9/configuring-npm/npmrc#auth-related-configuration&quot;&gt;documentaion&lt;/a&gt; for details.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Save and Restart Your Node-RED Instance: The new npm modules should now be visible in the Node-RED Palette Manager.&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/</id>
        <title>Custom Vuetify components for Dashboard 2.0</title>
        <summary>Expand your dashboard with the full collection of Vuetify components</summary>
        <updated>2023-10-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Vuetify is a library of UI components using Vue. This saves the developers of
Dashboard 2.0 a lot of time, but it can also help you, the end-user. As Vuetify
is now included, it can be used to include &lt;em&gt;any&lt;/em&gt; of their components. So in this
post we&#39;re going to use a few of these to teach you how to use any of them.&lt;/p&gt;
&lt;p&gt;Let&#39;s install the &lt;a href=&quot;https://dashboard.flowfuse.com/getting-started.html&quot;&gt;Dashboard 2.0 package&lt;/a&gt; if you want to follow along. When that&#39;s done, let&#39;s figure
out how to build custom components on dashboards.&lt;/p&gt;
&lt;h2 id=&quot;custom-components&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/#custom-components&quot;&gt;Custom components&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While going through the list of components on &lt;a href=&quot;https://vuetifyjs.com/en/components/&quot;&gt;Vuetify&lt;/a&gt;
there&#39;s several examples that aren&#39;t natively implemented in Dashboard 2.0.
One example we&#39;ll use in a dashboard in this post is the
&lt;a href=&quot;https://vuetifyjs.com/en/components/progress-circular/&quot;&gt;Progress circular&lt;/a&gt; to
build a count down timer.&lt;/p&gt;
&lt;p&gt;The documentation explains which elements one can change, in this case the size and
width. Having set those to the values you&#39;d want in your dashboard, the HTML is
generated for you, in my case it&#39;s:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-15&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-15&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-progress-circular&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;model-value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;20&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;128&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-progress-circular&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-15&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;using-the-template-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/#using-the-template-node&quot;&gt;Using the template node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like the &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/template/&quot;&gt;template core node&lt;/a&gt;, the dashboard package
comes with &lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html&quot;&gt;a template node of its own&lt;/a&gt;.
If we take the HTML from the Vuetify docs pages and copy it in a template node
the spinner will show up on the dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Custom widget on Dashboard 2.0&quot; alt=&quot;&amp;quot;Custom widget on Dashboard 2.0&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/custom-element-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;dynamic-templates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/#dynamic-templates&quot;&gt;Dynamic templates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While a custom element on a page is cool, and shows you can inject arbitrary HTML
on a Dashboard, it&#39;s even better if we could make the element dynamic. So let&#39;s
start with a first dynamic element. The quickest way to get that done is have
an &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/inject/&quot;&gt;&lt;code&gt;Inject&lt;/code&gt;&lt;/a&gt; node output a random number every second.&lt;/p&gt;
&lt;p&gt;So let&#39;s hook up an Inject, with &lt;code&gt;msg.payload&lt;/code&gt;&#39;s output being a JSONata expression
&lt;code&gt;$round($random() * 100)&lt;/code&gt; to generate a random number. And let&#39;s make sure it
sends a message every second.&lt;/p&gt;
&lt;p&gt;Then we need to update the template node to the following snippet:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-37&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-37&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;v-progress-circular&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-model&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msg.payload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;128&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;12&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;v-progress-circular&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-37&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The difference is subtle, but important. Instead of hard-coding the &lt;code&gt;model-value&lt;/code&gt;
to 20, the tag has changed name and it&#39;s set to &lt;code&gt;msg.payload&lt;/code&gt;. The latter makes
the value dynamic.&lt;/p&gt;
&lt;p&gt;Changing &lt;code&gt;model-value&lt;/code&gt; to &lt;code&gt;v-model&lt;/code&gt; is due to leaking implementation details of
Dashboard 2.0. It uses VueJS to provide, among other features, easy updating of
components. If components are dynamic, &lt;em&gt;always use &lt;code&gt;v-model&lt;/code&gt;&lt;/em&gt;. This allows VueJS
to pick up changes made dynamically.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Progress spinner, random values&quot; alt=&quot;&amp;quot;Progress spinner, random values&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/random-progress-element.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;finishing-the-count-down-timer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/10/custom-vuetify-components-dashboard/#finishing-the-count-down-timer&quot;&gt;Finishing the count down timer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is mostly a programmers job, but it&#39;s not hard, so let&#39;s get to it. A button
would be great to reset the timer, and for the sake of this post we can hardcode
the deadline to 1m from the button press.&lt;/p&gt;
&lt;p&gt;When dragging in a button node, connect it to a &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/change/&quot;&gt;change&lt;/a&gt;
node. In the change node set the flow variable &lt;code&gt;flow.deadline&lt;/code&gt; to the timestamp. The
Inject node from earlier needs updating to inject the &lt;code&gt;flow.deadline&lt;/code&gt;. All that&#39;s
left is calculating how many seconds passed, and normalizing 60 seconds to the
range between 0-100.&lt;/p&gt;
&lt;p&gt;The complete flow is:&lt;/p&gt;
&lt;div id=&quot;nr-flow-174&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow174 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ce9bb8f74e3fc934&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;8fa772a709ae3316&#92;&quot;,&#92;&quot;dashboard&#92;&quot;:&#92;&quot;e5a3f4cdb11e5e3b&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;5bedf7f49d5a6037&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Progress spinner&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;v-progress-circular v-model=&#92;&#92;&#92;&quot;msg.payload&#92;&#92;&#92;&quot; :size=&#92;&#92;&#92;&quot;128&#92;&#92;&#92;&quot; :width=&#92;&#92;&#92;&quot;12&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-progress-circular&amp;gt;&#92;&#92;n&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;fwdInMessages&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8f3e6631414aa096&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject deadline&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;deadline&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;x&#92;&quot;:140,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;293cd6f9d727fa02&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bd9032719d24a53d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;8fa772a709ae3316&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Reset&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;deadline&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;61ef83d8b06ff626&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;61ef83d8b06ff626&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;deadline&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;date&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;293cd6f9d727fa02&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Secs since reset&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;($millis() - msg.payload)/1000&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:340,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9742da7e74fd3cd2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9742da7e74fd3cd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;range&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;24065a0aadb305e3&#92;&quot;,&#92;&quot;minin&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;maxin&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;minout&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;maxout&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;clamp&#92;&quot;,&#92;&quot;round&#92;&quot;:false,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Seconds to percentages&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ce9bb8f74e3fc934&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8fa772a709ae3316&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Group Name&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;5bedf7f49d5a6037&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;disp&#92;&quot;:true},{&#92;&quot;id&#92;&quot;:&#92;&quot;e5a3f4cdb11e5e3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;UI Name&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5bedf7f49d5a6037&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Page Name&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;e5a3f4cdb11e5e3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;8240fbe7c09bc81c&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;8240fbe7c09bc81c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Theme Name&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow174.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-174&#39;) })&lt;/script&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/rebranding-our-components/</id>
        <title>Updating our branding across GitHub, npm and Dockerhub</title>
        <summary>Renaming our packages and containers and what it means for our users</summary>
        <updated>2023-09-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/rebranding-our-components/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Following our rename to FlowFuse last month, we are about to take the next
set of steps to complete the rebrand. This time, focussed on the technical
assets we produce.&lt;/p&gt;
&lt;p&gt;Rebranding a company isn&#39;t a small undertaking, especially when your company
name is also your product name. When we announced our &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/&quot;&gt;new name last month&lt;/a&gt; we
prioritised updating the website, our documentation and social media presences.
All of the most visible things relating to the company name.&lt;/p&gt;
&lt;p&gt;But we knew that wasn&#39;t the whole job done. The name &lt;code&gt;flowforge&lt;/code&gt; still appears
in the technical resources we use and the artefacts we publish. Changing them
is not as simple a task as changing some words on a website, so it has taken a bit
more time to get our plans in place for this next step.&lt;/p&gt;
&lt;p&gt;I wanted to highlight the set of changes we&#39;ll be making in the coming days to
complete this migration. For the vast majority of users, expecially those using
FlowFuse Cloud, these changes will be completely transparent.&lt;/p&gt;
&lt;p&gt;However, if you are contributing to any of our open source components, or consuming
our npm or Docker packages directly, then please read on.&lt;/p&gt;
&lt;p&gt;There are four areas we need to migrate.&lt;/p&gt;
&lt;h3 id=&quot;github-organization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/rebranding-our-components/#github-organization&quot;&gt;GitHub Organization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As a company everything we do revolves around our GitHub Organization. Our
source code, release planning, this website, and far more all live there.&lt;/p&gt;
&lt;p&gt;Step one of our migration will be renaming the organization to &lt;code&gt;FlowFuse&lt;/code&gt;, so instead
of &lt;code&gt;https://github.com/flowforge&lt;/code&gt; we will now live at &lt;code&gt;https://github.com/FlowFuse&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Renaming organizations on GitHub, whilst not something done lightly, is well catered
for. Many existing urls should get automatically redirected - so any existing
links will still work. We will, of course, do the work to update any urls in our docs.&lt;/p&gt;
&lt;h3 id=&quot;npm-package-names&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/rebranding-our-components/#npm-package-names&quot;&gt;NPM package names&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We publish a number of packages to the public Node.js Package Manager (npm) repository
under the &lt;code&gt;@flowforge&lt;/code&gt; name.&lt;/p&gt;
&lt;p&gt;After this week&#39;s release is done, we&#39;ll be updating all of our packages to publish
under the &lt;code&gt;@flowfuse&lt;/code&gt; name and no longer updating the packages under the old name.&lt;/p&gt;
&lt;p&gt;This will impact anyone who has installed any of our components directly from &lt;code&gt;npm&lt;/code&gt;. For
example, the Device Agent or Node-RED Dashboard 2.0.&lt;/p&gt;
&lt;p&gt;We will provide specific upgrade instructions for each of the affected components once
the move is done.&lt;/p&gt;
&lt;h3 id=&quot;docker-images&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/rebranding-our-components/#docker-images&quot;&gt;Docker Images&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We publish container images to Dockerhub under the &lt;code&gt;flowforge&lt;/code&gt; name. Once
we&#39;ve updated our npm package names, we&#39;ll also be updating our container tags
to use the new name.&lt;/p&gt;
&lt;p&gt;If you are using our helm or Docker Compose projects, we&#39;ll have a new release that
will help get you moved over to the new image names. Likewise our Digital Ocean
and AWS Marketplace offerings will be updated - and instructions provided for existing
users to migrate over.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/rebranding-our-components/#flowfuse-cloud&quot;&gt;FlowFuse Cloud&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The final step we have to make is to move FlowFuse Cloud over to its new home
at &lt;code&gt;app.flowfuse.com&lt;/code&gt;. We have to co-ordinate the update with all of our customers
who use SSO to login to ensure they can continue to access the platform.&lt;/p&gt;
&lt;p&gt;Once that is done, it will be a seamless transition for everyone. Existing Node-RED
instances will continue to use the &lt;code&gt;*.flowforge.cloud&lt;/code&gt; domain, but then all new
instances will use the &lt;code&gt;*.flowfuse.cloud&lt;/code&gt; domain.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/</id>
        <title>How ChatGPT improves Node-RED Developer Experience</title>
        <summary>Language models have made an impact in the Node-RED community</summary>
        <updated>2023-09-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;ChatGPT has the potential to have a significant impact on the Node-RED community. It is a powerful language model that can be used to generate flows, interpret them, and provide documentation, maybe soon even write the flow! The combination of ChatGPT, or generative AI at large, with Node-RED can significantly improve the developer experience with Node-RED. In this post we’ll review what the community has already built.&lt;/p&gt;
&lt;h2 id=&quot;how-generative-ai-like-chatgpt-is-used-for-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/#how-generative-ai-like-chatgpt-is-used-for-node-red&quot;&gt;How generative AI like ChatGPT is used for Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;function-node-%3C3-chatgpt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/#function-node-%3C3-chatgpt&quot;&gt;Function node &amp;lt;3 ChatGPT&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ChatGPT, and other models, can write code for you, much like &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub CoPilot&lt;/a&gt; or &lt;a href=&quot;https://about.gitlab.com/gitlab-duo/&quot;&gt;GitLab Duo&lt;/a&gt;. As Node-RED is ‘low-code’ the ability for generative AI to write the required code for you creates a paradigm shift to ‘no-code’!&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Example of Chat GPT to generate contents of a function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/chatgpt-fcn-example.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;At FlowFuse we’ve written about this &lt;a href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/&quot;&gt;before&lt;/a&gt;, and published a &lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt&quot;&gt;plugin&lt;/a&gt;. This node allows flow developers to be more productive and efficient. While this works only for the function node, there’s countless other possibilities to describe a flow in text and import a ChatGPT generated flow that are on the horizon!&lt;/p&gt;
&lt;h3 id=&quot;flow-interpretation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/#flow-interpretation&quot;&gt;Flow Interpretation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When developing larger projects with multiple tabs, it’s important to understand what each tab contributes to the full project. This problem is compounded when the flows are developed by a team or the time between the flow was last updated is higher.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ChatGPT Flow Interpretation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://raw.githubusercontent.com/node-red-jp/node-red-contrib-plugin-chatgpt/main/infotab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/kazuhitoyokoi/&quot;&gt;Kazuhito-san&lt;/a&gt; wrote a module for Node-RED to interpret the flow, nodes, and their order into a well structured documentation. Through a click of a button it&#39;s generated by the well-known OpenAI
model. This is especially interesting as it&#39;s thus able regenerate it when changes were made by the developers.&lt;/p&gt;
&lt;p&gt;It’s a plugin that requires very little setup, and can be found in the &lt;a href=&quot;https://www.npmjs.com/package/node-red-contrib-plugin-chatgpt&quot;&gt;flow library&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lots-of-plugins&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/#lots-of-plugins&quot;&gt;Lots of plugins&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The ecosystem of Node-RED has always been a fast adopter of new technology. There&#39;s
nodes for &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-chatgpt&quot;&gt;ChatGPT&lt;/a&gt;,
&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-bard&quot;&gt;Google&#39;s Bard&lt;/a&gt;, and many
more. These plugins genernally let you build on top of these models, and don&#39;t
nessecairly improve the developer experience. It&#39;s however a great source of
inspiration!&lt;/p&gt;
&lt;h3 id=&quot;further-discussion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/chatgpt-for-node-red-developers/#further-discussion&quot;&gt;Further discussion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These were three examples of how generative AI is used in the Node-RED community. Please let us know if you&#39;re using ChatGPT or other AI models with Node-RED? And what would be the killer feature for Node-RED and AI?&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/flow-viewer/</id>
        <title>Share &amp; Preview Flows on flows.nodered.org</title>
        <summary>FlowFuse has just contributed an interactive &quot;Flow Viewer&quot; to flows.nodered.org, allowing users to preview flows, and embed them in articles &amp; forum posts.</summary>
        <updated>2023-09-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/flow-viewer/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;For years, Node-RED&#39;s website has provided functionality to share flows through &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;flows.nodered.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This week, we at FlowFuse have contributed a new feature to the site that allows users to visually preview those flows, and embed/share those flows in articles and on forum posts.&lt;/p&gt;
&lt;h2 id=&quot;visual-flow-previews&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/#visual-flow-previews&quot;&gt;Visual Flow Previews&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A huge thank you for this work needs to go Gerrit Riessen&#39;s work published on his &lt;a href=&quot;https://blog.openmindmap.org/&quot;&gt;Open Mind Map Blog&lt;/a&gt;. He recently open-sourced some great work to GitHub (&lt;a href=&quot;https://github.com/gorenje/node-red-flowviewer-js&quot;&gt;repo&lt;/a&gt;), and with some adaptation and collaboration, we&#39;ve been able to utilise this as a foundation for the functionality we&#39;ve added into the flows site.&lt;/p&gt;
&lt;p&gt;Adding this to &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;flows.nodered.org&lt;/a&gt; will make it far easier to learn how others use Node-RED, and to share your own flows with others too. The embedding functionality should also make talking about Node-RED in your own articles &amp;amp; forums much easier.&lt;/p&gt;
&lt;h3 id=&quot;example%3A-simple-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/#example%3A-simple-flow&quot;&gt;Example: Simple Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#39;s a demonstration of a simple &lt;code&gt;Inject&lt;/code&gt; &amp;gt; &lt;code&gt;Debug&lt;/code&gt; node:&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;200px&quot; src=&quot;https://flows.nodered.org/flow/500ee13719e54e42493c8ec96fa733b6/share?height=100&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;example%3A-subflows%2C-groups%2C-links-%26-switches&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/#example%3A-subflows%2C-groups%2C-links-%26-switches&quot;&gt;Example: Subflows, Groups, Links &amp;amp; Switches&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#39;s a non-functional flow that just demonstrates how FlowViewer renders the range of node types available in Node-RED:&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;500px&quot; src=&quot;https://flows.nodered.org/flow/82a8602b615740491d30c083e5292e5f/share&quot; allow=&quot;clipboard-read; clipboard-write&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;sharing-%26-embedding-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/flow-viewer/#sharing-%26-embedding-flows&quot;&gt;Sharing &amp;amp; Embedding Flows&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Any flow on &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;flows.nodered.org&lt;/a&gt; now has a &lt;code&gt;Share Flow&lt;/code&gt; option in the &lt;code&gt;Actions&lt;/code&gt; section on the right side of the flows page. Clicking this will provide you with an iframe like:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-35&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-35&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://flows.nodered.org/flow/7c2dd3ccde70746a40ef8f5aa58c591c/share&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;clipboard-read; clipboard-write&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-35&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Which you can paste/embed into any website or blog post. Nick has also &lt;a href=&quot;https://discourse.nodered.org/t/previewing-flows-on-the-flow-library/&quot;&gt;enabled the Node-RED forums to support these embeds too&lt;/a&gt;, and is also how we&#39;ve embeded the above flows too.&lt;/p&gt;
&lt;p&gt;If you want more control over the sizing of the viewer, you can also include a &lt;code&gt;?height=&lt;/code&gt; query parameter on the &lt;code&gt;src&lt;/code&gt; value of the &lt;code&gt;iframe&lt;/code&gt;. You may also need to hardcode the &lt;code&gt;height&lt;/code&gt; property of the &lt;code&gt;iframe&lt;/code&gt; itself to account for this change, depending on where you&#39;re embedding it to. For example:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-42&quot;&gt;
  &lt;pre class=&quot;language-html&quot;&gt;&lt;code id=&quot;code-42&quot; class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;250px&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://flows.nodered.org/flow/7c2dd3ccde70746a40ef8f5aa58c591c/share?height=100&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;clipboard-read; clipboard-write&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-42&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We know it&#39;s still not perfect, and there&#39;s plenty more we can do with it, but hopefully this is a welcome contribution to the Node-RED community.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/</id>
        <title>Modernize your legacy industrial data. Part 2.</title>
        <summary>Explore strategies, challenges, and smart processing techniques for enhancing legacy industrial data utilization in the IIoT era with Node-RED.</summary>
        <updated>2023-09-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/"/>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/&quot;&gt;part 1 of this series&lt;/a&gt;, I introduced the topic of working with legacy industrial data from the likes of Modbus and older, non IIoT protocols and putting it to work in an IIoT world. We looked at some of the challenges and how Node-RED with &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt; node can help.&lt;/p&gt;
&lt;p&gt;In this article, I will dive a little deeper into the topic and discuss some of the finer details. I hope to demonstrate a smarter approach that can make a huge difference to data accuracy, performance and maintainability while significantly reducing developer time. Not only that, ending with a no-code solution.&lt;/p&gt;
&lt;h2 id=&quot;obtaining-industrial-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#obtaining-industrial-data&quot;&gt;Obtaining Industrial Data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to convert the legacy data to a format more suited to IIoT we first need to &lt;em&gt;grab&lt;/em&gt; that data.&lt;/p&gt;
&lt;p&gt;Node-RED has core nodes that can help you and many more contribution nodes exist that provide access to a wide range of industrial devices. To give you an idea, &lt;code&gt;node-red-contrib-modbus&lt;/code&gt;, &lt;code&gt;node-red-contrib-s7comm&lt;/code&gt;, &lt;code&gt;node-red-contrib-omron-fins&lt;/code&gt;, &lt;code&gt;node-red-contrib-mcprotocol&lt;/code&gt;, &lt;code&gt;node-red-contrib-df1&lt;/code&gt; and &lt;code&gt;node-red-contrib-cip-st-ethernet-ip&lt;/code&gt; are just some of the PLC data access nodes available.&lt;/p&gt;
&lt;p&gt;But getting the data is just the beginning, it&#39;s the methods and considerations you need to make that can make the difference between success and failure. Read on...&lt;/p&gt;
&lt;h2 id=&quot;data-consistency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#data-consistency&quot;&gt;Data consistency&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An often overlooked aspect of working with legacy industrial data is the consistency of the data being read. In the context of this article, consistency means that the multiple values that make up a related data set are read in a way that they are all valid to one another at the point in time it was read.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at a simple example. We have a process PLC recording production metrics and wish to get this data from its Modbus interface for reporting and decision making. The PLC has 5 values that we need to read:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Register&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Data Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1, 2&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Part Count&lt;/td&gt;
&lt;td&gt;UINT32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3, 4&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;Cycle Time (sec)&lt;/td&gt;
&lt;td&gt;UINT32/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5, 6&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Production Time (sec)&lt;/td&gt;
&lt;td&gt;UINT32/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7, 8&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;Run Time (sec)&lt;/td&gt;
&lt;td&gt;UINT32/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9, 10&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Stoppage Time (sec)&lt;/td&gt;
&lt;td&gt;UINT32/100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In the above data sample, we can see the total production time is 30 seconds and the run time is 20 seconds. The expectation is that the Stoppage Time should be 10 seconds. However, as we can see, Stoppage Time in this sample is 11 seconds. That is because this data is not consistent.&lt;/p&gt;
&lt;h3 id=&quot;why-is-the-data-inconsistent%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#why-is-the-data-inconsistent%3F&quot;&gt;Why is the data inconsistent?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The most common reason for the data inconsistency is that the data is being read from the PLC while the PLC is running. The data is changing as it is being read.&lt;/p&gt;
&lt;p&gt;Typically this happens when a developer, unfamiliar with the protocol or end device, begins by reading the data individually. Here is how this journey might look:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 1: individual reads&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;image showing 10 individual reads&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-demo1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;That is a lot of nodes and a lot of duplication!&lt;/p&gt;
&lt;p&gt;What is worse, is that the developer continues down this path and begins converting the data ready for publishing to MQTT. Here is how this might evolve:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 2: individual reads with data processing&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Image showing 10 individual reads with data processing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-10polls.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Yippie! We have the data, it works, we publish it to MQTT, job done. Right?&lt;/p&gt;
&lt;p&gt;Unfortunately, no. The data is inconsistent.&lt;/p&gt;
&lt;h3 id=&quot;so-whats-the-big-deal%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#so-whats-the-big-deal%3F&quot;&gt;So whats the big deal?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inconsistent data is not useful data and errors can get compounded over time. This leads to bad decisions being made and a loss of confidence in the data. Ultimately, this leads to the data being ignored and the opportunities to make improvements are lost. Loss of improvements means loss of money!&lt;/p&gt;
&lt;p&gt;Not only that, from a developer or maintainers perspective, it has many problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lots of error prone manual configuration (yes, I made several mistakes while creating the example)&lt;/li&gt;
&lt;li&gt;Hard coded register addresses&lt;/li&gt;
&lt;li&gt;Duplication&lt;/li&gt;
&lt;li&gt;Inextensible - what if we need to read more registers?&lt;/li&gt;
&lt;li&gt;Inconsistent data - as discussed above&lt;/li&gt;
&lt;li&gt;Slow - each read takes time&lt;/li&gt;
&lt;li&gt;Inefficient use of network bandwidth - each read requires a request and response packet&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-can-we-make-the-data-consistent%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#how-can-we-make-the-data-consistent%3F&quot;&gt;How can we make the data consistent?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The most obvious solution is to stop the PLC before reading the data.
However, I am faily certain your boss will not be super pleased with stopping the manufacturing process.
The next best thing is for the PLC to sample and store the data in an internal memory buffer, waiting, unchanging, to be collected. Unfortunately, this too is not always possible either due to limited in-house skills, locked down PLCs or simply because the PLC does not have the memory to store the data.&lt;/p&gt;
&lt;p&gt;The next best thing to do is to read relative data as quickly as possible and in one block.&lt;/p&gt;
&lt;h3 id=&quot;a-quick-side-bar-(timing-is-...-everything)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#a-quick-side-bar-(timing-is-...-everything)&quot;&gt;A quick side-bar (timing is ... everything)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In many protocols, including Modbus, data must be polled. Each poll, depending on many factors, can take a number of milliseconds.&lt;/p&gt;
&lt;p&gt;Lets say, on a relatively quiet serial network, a single register poll takes 25 milliseconds (assume 9600 baud, 1 byte/ms, request packet size 8 bytes, response packet size 7 bytes, 10ms latency for the PLC to receive, process and respond to the request)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If we read 10 registers individually, then the time taken to read the 10 registers is 250 milliseconds.&lt;/li&gt;
&lt;li&gt;If we actually needed a more realistic number of registers, say 32, then the time taken to read them individually is a whopping 800 milliseconds. In the world of PLCs, that is an eternity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, lets look at that from a different approach. If we were to read the 32 registers in one go, the time taken based on the above constants would be 87 milliseconds. That is over 9 times faster than reading the registers individually. The improvements don&#39;t stop there either, the number of total bytes transferred on your network is reduced by 84% and, more importantly, the data is consistent since it was read from the same scan of the PLC scan.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 3: A comparison of individual reads vs block reads&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;A data table comparing polls vs block read&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-table.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;OK, back to the topic at hand.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-data-in-a-more-consistent-way&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#getting-the-data-in-a-more-consistent-way&quot;&gt;Getting the data in a more consistent way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the same example as above but this time we are reading the data in one go:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 4: Getting data in one block&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;image showing 1 read for 10 registers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-demo1b.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Note how much simpler this is? Not only that, it is easier to maintain, faster, more extensible and most importantly, the data is consistent.&lt;/p&gt;
&lt;p&gt;Great, lets move on.&lt;/p&gt;
&lt;h2 id=&quot;processing-the-data-in-readiness-for-iiot%3A-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#processing-the-data-in-readiness-for-iiot%3A-mqtt&quot;&gt;Processing the data in readiness for IIoT: MQTT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have good data, we need to process it in readiness for IIoT. In this example, we are going to publish the data to an MQTT broker as individual topics. This is a common approach as it allows the data to be easily consumed by other systems and applications. Using &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt; we can easily convert the data into more meaningful formats.&lt;/p&gt;
&lt;p&gt;The first, instinctive approach is to fan out the data and process it individually:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 5: block reads, individual processing&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;image showing 1 modbus poll with individual processing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-1poll-fixed.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This may be fine for a handful of registers but it soon becomes unwieldy and unmaintainable.&lt;/p&gt;
&lt;p&gt;But lets be smarter about this. We know that the data is consistent and we know that we can read it in one go. So, lets process it in one go too:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image 6: block reads, smart processing, no-code solution&lt;/em&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;image showing 1 modbus poll with smart processing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-pt2-1poll-extensible.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;node-red-in-production&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#node-red-in-production&quot;&gt;Node-RED in Production&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is a powerful tool widely used in IoT and IIoT industries, including manufacturing, automotive, textiles, and building management. It excels at collecting, transforming, visualizing, and analyzing data. While integrating Node-RED into production environments offers numerous benefits, it often involves complex tasks such as deploying the server, managing security, and ensuring scalability. These initial setup challenges can be overwhelming and time-consuming.&lt;/p&gt;
&lt;p&gt;FlowFuse simplifies these tasks by providing a unified platform for managing all Node-RED instances. It enhances collaboration, ensures security, and supports scalability, making deployment and management more efficient. With features like &lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/&quot;&gt;snapshots&lt;/a&gt;, team collaboration tools, one-click deployment, and &lt;a href=&quot;https://flowfuse.com/docs/user/user-settings/#security&quot;&gt;multi-factor authentication&lt;/a&gt;, FlowFuse streamlines the process and enhances the operational capabilities of Node-RED in production settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and experience FlowFuse&#39;s features&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data-part2/#wrap-up&quot;&gt;Wrap up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hope this article has given you some food for thought and some ideas on not only simplifying your journey to IIoT but also the pitfalls to avoid along the way.&lt;/p&gt;
&lt;p&gt;A parting thought, there are times when the data is not contiguous. There are ways to deal with this too but that is for another day.&lt;/p&gt;
&lt;p&gt;P.S. I will post the flows used for the examples above in the comments below. If you have any questions or comments, please reach out there too.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/tulip-event-report/</id>
        <title>Tulip Operation Calling Event Report</title>
        <summary>Thoughts and insighs from Tulip&#39;s recent customer event</summary>
        <updated>2023-09-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/tulip-event-report/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This week I attended the Tulip event called &lt;a href=&quot;https://www.operationscalling.com/&quot;&gt;Operations Calling&lt;/a&gt; in Boston. Here are some quick observations from the event.&lt;/p&gt;
&lt;p&gt;For those that might not know &lt;a href=&quot;https://tulip.co/&quot;&gt;Tulip&lt;/a&gt;, they are a Boston based company focused on frontline operations in the manufacturing and industrial automation industry. They provide the software to help factory workers be more efficient at their job. Some people refer to this category as MES but Tulip avoids this term since MES can carry a lot of negative baggage from legacy MES vendors.&lt;/p&gt;
&lt;p&gt;Some quick thoughts on the event:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I would estimate about 300 people attended the event. It was held at Tulip’s office, which is actually in an old Ford factory. The offices and environment were very cool.&lt;/li&gt;
&lt;li&gt;There was a large emphasis on Tulip partners and the ecosystem. Tulip knows it needs to be open and play well with others. There were 27 different vendors showing in their partner pavillion. Pretty impressive given the size of Tulip.&lt;/li&gt;
&lt;li&gt;Tulip has a no-code environment for setting up their software. However, they realize you also need low-code, like Node-RED, for integrating hardware and software into Tulip. I attended two sessions that discussed how Node-RED is an important part of the Tulip integration and customization strategy. Node-RED was also being used in some of their demos stations.&lt;/li&gt;
&lt;li&gt;Tulip talks about ‘citizen developers’ and ‘composable apps’. This is the future of manufacturing. Organizations need to start thinking in terms of smaller applications that do a specific task that can also be rolled up into something bigger at a later time. These small applications need to be developed by the people closest to the problem, not the IT team or a system integrator.&lt;/li&gt;
&lt;li&gt;During the closing panel, it was stated that ‘Today, Excel is the most popular digital automation platform used in industry.’ There are a lot of spreadsheets being used to collect and visualize data. However, the industry needs to find a better way. Node-RED is an important part of the solution. The people who can run Excel spreadsheets can easily use Node-RED. However, using Node-RED will let them do even more than what Excel allows them to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Operation Calling was definitely an event worth attending and I hope to return next year.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/</id>
        <title>Modernize your legacy industrial data</title>
        <summary>Working with legacy industrial protocol data from the likes of Modbus and older, non IIoT protocols and putting it to work in an IIoT world.</summary>
        <updated>2023-09-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/"/>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Industrial systems generate valuable data, but legacy protocols like Modbus or non-IIoT standards often make it hard to use. Bridging this gap is essential to connect traditional systems with the modern Industrial Internet of Things (IIoT).&lt;/p&gt;
&lt;p&gt;Whether it’s Modbus registers, serial communication without a protocol, or standards like Siemens S7 and Mitsubishi MC-Protocol, the challenge lies in making sense of this raw information. With tools like Node-RED and the node-red-contrib-buffer-parser, you can turn complex, outdated data streams into usable formats that power IIoT innovation.&lt;/p&gt;
&lt;h3 id=&quot;legacy-industrial-data%3A-modbus&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#legacy-industrial-data%3A-modbus&quot;&gt;Legacy Industrial Data: Modbus&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modbus is one of the most widely used industrial protocols. Originally developed in the late 1970s, it has been a popular choice for industrial communication ever since. However, its data format can be challenging to work with in the context of modern IIoT applications. Modbus typically represents data in 16-bit unsigned registers, making it necessary to convert this data into more usable formats like Signed integer, Float, Signed and Unsigned Long, String, or even individual bits.&lt;/p&gt;
&lt;h3 id=&quot;a-short-primer-on-data-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#a-short-primer-on-data-types&quot;&gt;A short primer on data types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we dive into how to make sense of Modbus data, let&#39;s take a quick look at some of the common data types we have to deal with.&lt;/p&gt;
&lt;h4 id=&quot;16-bit-unsigned&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#16-bit-unsigned&quot;&gt;16-bit unsigned&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;16-bit unsigned data is an integer that can only be positive. It can represent values from 0 to 65535. For example, the number 12345 is represented as &lt;code&gt;0x3039&lt;/code&gt; in hexadecimal or &lt;code&gt;0011000000111001&lt;/code&gt; in binary.&lt;/p&gt;
&lt;h4 id=&quot;16-bit-signed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#16-bit-signed&quot;&gt;16-bit signed&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;16-bit signed data is an integer that can be positive or negative. It can represent values from -32768 to 32767. For example, the number -12345 is represented as &lt;code&gt;0xCFC7&lt;/code&gt; in hexadecimal or &lt;code&gt;1100111111000111&lt;/code&gt; in binary.&lt;/p&gt;
&lt;h4 id=&quot;32-bit-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#32-bit-data&quot;&gt;32-bit data&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;32-bit data, like 16-bit data can mean many things. It could be signed or unsigned, or even a floating point number. For example, the number 12345 is represented as &lt;code&gt;0x00003039&lt;/code&gt; in hexadecimal or &lt;code&gt;00000000000000000011000000111001&lt;/code&gt; in binary. Typically, 32-bit data is represented as two 16-bit registers. Therefore, when dealing with 32-bit data, you need to combine two 16-bit registers to get the full value.&lt;/p&gt;
&lt;h4 id=&quot;endianness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#endianness&quot;&gt;Endianness&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Endianness, particularly in the context of data communications, refers to the order of bytes and how they are stored or transmitted. There are two types of endianness: big-endian (BE) and little-endian (LE). In big-endian, the most significant byte is first, while in little-endian, the least significant byte is first. For example, the number 12345 is represented as &lt;code&gt;0x3039&lt;/code&gt; in a big-endian word and &lt;code&gt;0x3930&lt;/code&gt; in little-endian word.  This can often cause confusion and complicate the process of converting Modbus data into more usable formats.&lt;/p&gt;
&lt;h3 id=&quot;node-red-and-node-red-contrib-buffer-parser-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#node-red-and-node-red-contrib-buffer-parser-to-the-rescue&quot;&gt;Node-RED and node-red-contrib-buffer-parser to the rescue&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED is an open-source flow-based development tool for visual programming. It&#39;s particularly well-suited for IIoT applications because of its versatility and extensive library of nodes. One such node, &lt;code&gt;node-red-contrib-buffer-parser&lt;/code&gt;, provides a solution to the legacy data conversion challenge.&lt;/p&gt;
&lt;p&gt;This powerful Node-RED module allows you to parse a Buffer of bytes or an Array of integer data (which, by no coincidence, the popular module &lt;code&gt;node-red-contrib-modbus&lt;/code&gt; outputs), and convert it into various data types. It can output pretty much any data type, including byte-swapped data, WORD swapped data, masked/shifted/scaled data, and even individual bits.&lt;/p&gt;
&lt;p&gt;Here&#39;s a quick overview of how it works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Parsing&lt;/strong&gt;: Start by setting up a Modbus READ node in Node-RED to retrieve data from your industrial device. Then, use the buffer parser node to parse the Modbus data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Conversion&lt;/strong&gt;: With the buffer parser, you can easily convert the 16-bit unsigned data into more meaningful formats. Whether you need to translate it into Float, Long, String, or even extract specific bits, this tool makes the process straightforward.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Publishing to MQTT, influxDB, a dashboard, an IIoT system&lt;/strong&gt;: Once your data is in a usable format, Node-RED enables you to publish it to many places. MQTT (Message Queuing Telemetry Transport), a popular protocol for IIoT communication is a perfect example. This makes your data accessible to other IIoT systems and applications for further analysis and action.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;unlocking-the-potential-of-legacy-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#unlocking-the-potential-of-legacy-data&quot;&gt;Unlocking the Potential of Legacy Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By leveraging Node-RED and buffer parser, you can bridge the gap between legacy industrial protocols and the IIoT world. This means you can extract valuable insights from your existing infrastructure without the need for costly hardware upgrades or replacements.&lt;/p&gt;
&lt;p&gt;In the era of the Industrial Internet of Things, making sense of your industrial data is no longer a daunting challenge. With the right tools approach, you can unlock the full potential of your legacy data and drive efficiency, productivity, and innovation in your industrial processes. Yey!&lt;/p&gt;
&lt;h3 id=&quot;3-quick-demos-of-node-red-and-the-buffer-parser-node-in-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#3-quick-demos-of-node-red-and-the-buffer-parser-node-in-action&quot;&gt;3 quick demos of Node-RED and the buffer parser node in action&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here are 3 quick demonstrations that barely scratch the surface of possibilities:&lt;/p&gt;
&lt;h4 id=&quot;example-1%3A-modbus-to-mqtt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#example-1%3A-modbus-to-mqtt&quot;&gt;Example 1: Modbus to MQTT&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Converting an array of 16-bit unsigned integers to String, Float and a scaled integer and passing them to an MQTT broker in 4 nodes!
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Legacy data to MQTT&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-to-mqtt.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;example-2%3A-modbus-to-influxdb&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#example-2%3A-modbus-to-influxdb&quot;&gt;Example 2: Modbus to InfluxDB&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Converting an array of 16-bit unsigned integers to String, Float and a scaled integer for publishing to influxDB!
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Legacy data to influxDB&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-to-influx.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Legacy data to influxDB2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-to-influx2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;example-3%3A-modbus-data-on-a-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#example-3%3A-modbus-data-on-a-dashboard&quot;&gt;Example 3: Modbus data on a dashboard&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Converting an array of 16-bit unsigned integers to String, Float and a scaled integer for publishing to a dashboard!
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Legacy data to dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/industrial-legacy-data-to-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;simplify-your-node-red-operations-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#simplify-your-node-red-operations-with-flowfuse&quot;&gt;Simplify Your Node-RED Operations with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While Node-RED is a fantastic tool for data collection, transformation, and analysis, integrating it into a production environment can sometimes feel like navigating a maze. Whether you’re deploying Node-RED on a server, ensuring secure remote access for your team, or managing a sprawling network of thousands of instances, it’s easy to feel overwhelmed.&lt;/p&gt;
&lt;p&gt;That’s where FlowFuse steps in to make your life easier. FlowFuse is designed to tackle these challenges head-on. It enhances Node-RED with features that simplify collaboration, strengthen security, and provide scalable deployment options. Imagine having a robust system that not only keeps your Node-RED applications running smoothly but also scales effortlessly with your needs. With FlowFuse, you gain access to a comprehensive suite of production-ready &lt;a href=&quot;https://flowfuse.com/platform/features/&quot;&gt;features&lt;/a&gt; designed to streamline your Node-RED workflows and boost overall performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and experience FlowFuse&#39;s features&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;learn-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/modernize-your-legacy-industrial-data/#learn-more&quot;&gt;Learn More&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We will be publishing follow-up blog posts with more details, best practices and examples on how to use Node-RED to make sense of your industrial data. In the meantime, you can learn more about these tools by visiting the following links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/node-red/&quot;&gt;Node-RED blog posts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLpcyqc7kNgp09XeRx_cae1fEIOloPqM1C&quot;&gt;Node-RED videos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-buffer-parser&quot;&gt;Buffer Parser Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/community-news-09/</id>
        <title>Community News September 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-09-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/community-news-09/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for September 2023, a monthly roundup of what’s been happening with FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;new-name&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#new-name&quot;&gt;New Name&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The big news this month is that &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/&quot;&gt;FlowForge is now FlowFuse&lt;/a&gt;. Yes, we have changed our name but we are still focus on delivering great products for the Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;new-releases&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#new-releases&quot;&gt;New Releases&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Node-RED 3.1 has been &lt;a href=&quot;https://nodered.org/blog/2023/09/06/version-3-1-released&quot;&gt;released&lt;/a&gt;. Among the changes are Mermaid chart support, locking flows, and much more.&lt;/li&gt;
&lt;li&gt;Last week, FlowFuse 1.11 was released. This release included personal access tokens for FlowFuse API and new tiers for FlowFuse Cloud, including a new starter tier.  Check out the details in our &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/&quot;&gt;announcement&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;celebrate-10-years-of-node-red-and-what%E2%80%99s-new-in-3.1-and-beyond&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#celebrate-10-years-of-node-red-and-what%E2%80%99s-new-in-3.1-and-beyond&quot;&gt;Celebrate 10 Years of Node-RED and What’s New in 3.1 and Beyond&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hard to believe that Node-RED was launched 10 years ago. We want to celebrate this great accomplishment and also show off the new Node-RED 3.1 release. Join Nick O&#39;Leary for the 10 year celebration and here what is coming next.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/node-red-10-years/&quot;&gt;Sign-up today&lt;/a&gt; to join us on September 21.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The Node-RED Dashboard 2.0 project is making excellent progress. Two updates were published in the last month. Make sure you check out the latest release and provide feedback.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/&quot;&gt;Dynamic Markdown, Tables &amp;amp; Notebooks with Dashboard 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/&quot;&gt;Dashboard 2.0 - Community Update&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/09/bosch-rexroth-announce/&quot;&gt;FlowFuse announces a Node-RED stack for Industry 4.0 applications on Bosch Rexroth ctrlX Automation&lt;/a&gt; - a fully supported Node-RED stack for Bosch customers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/08/aws-marketplace-announce/&quot;&gt;FlowFuse is now available on the AWS Marketplace&lt;/a&gt; - making it easier to run FlowFuse on the AWS cloud.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/08/open-source-is-a-tier-not-competition/&quot;&gt;Our Open Source offering is a tier, not our competition&lt;/a&gt; - some insight from our CEO into our open source strategy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/&quot;&gt;Why the Automation Pyramid blocks digital transformation - The Role of Unified Namespace&lt;/a&gt; - some insight from the FlowFuse product manager into the role of a Unified Namespace.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A new plugin for the generation of &lt;a href=&quot;https://flows.nodered.org/node/@node-red-matter/node-red-matter&quot;&gt;Matter devices witin Node-RED&lt;/a&gt; has been published.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/community-news-09/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4958271004&quot;&gt;Developer Relations Engineer - Manufacturing &amp;amp; Industrial Automation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/bosch-rexroth-announce/</id>
        <title>FlowFuse announces a Node-RED stack for Industry 4.0 applications on ctrlX AUTOMATION</title>
        <summary>Rexroth ctrlX now have fully supported Node-RED stack available for production use</summary>
        <updated>2023-09-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/bosch-rexroth-announce/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse is pleased to announce they are now offering Node-RED plus select third party nodes from the Bosch Rexroth ctrlX World marketplace.&lt;/p&gt;
&lt;p&gt;FlowFuse is pleased to announce they are now offering Node-RED plus select third party nodes from the &lt;a href=&quot;https://developer.community.boschrexroth.com/t5/Store-and-How-to/FlowFuse-Node-RED/ba-p/82135&quot;&gt;Bosch Rexroth ctrlX Store&lt;/a&gt; marketplace. Rexroth customers building Industry 4.0 applications will now have a trusted vendor, in FlowFuse, to provide support and updates for using open source Node-RED in production. By partnering with FlowFuse, customers can reduce their risk of using Node-RED in production by relying upon FlowFuse Node-RED experts to assist with any development or production issues.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodered.org/&quot;&gt;Node-RED&lt;/a&gt; is a popular open source low-code development environment widely used in industries for collecting and processing industrial data to deliver Industry 4.0 applications. FlowFuse is uniquely positioned to partner with ctrlX customers looking to use Node-RED in production. FlowFuse CTO Nick O’Leary is the co-creator and project leader of Node-RED. FlowFuse employs many Node-RED experts who have years of experience helping customers with successful deployment of Node-RED applications.&lt;/p&gt;
&lt;p&gt;The FlowFuse package offered in the ctrlX World marketplace will provide ctrlX customers the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for Node-RED development and production deployments&lt;/li&gt;
&lt;li&gt;Support for third party nodes of popular industrial protocols including: Modbus, OMRON, S7 and MC Protocol.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse is the only vendor providing professional technical support for Node-RED on the ctrlX platform.&lt;/p&gt;
&lt;p&gt;The package is available today at ctrlX World. Interested customers should contact their Rexroth sales representative for purchasing details. Interested customers can also contact FlowFuse directly at &lt;a href=&quot;mailto:sales@flowfuse.com/&quot;&gt;sales@flowfuse.com&lt;/a&gt; for additional information about the offering.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/</id>
        <title>Dynamic Markdown, Tables &amp; Notebooks with Dashboard 2.0</title>
        <summary>A dive into the new features available in 0.4.0 - The &quot;Notebook&quot; Layout and new dynamic Markdown &amp; Table widgets.</summary>
        <updated>2023-09-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Whilst we&#39;re still busy backporting through the existing Dashboard 1.0 features, we did want to highlight some new features we&#39;ve built in Dashboard 2.0 released this week.&lt;/p&gt;
&lt;p&gt;In our v0.4.0 release, we&#39;ve introduced a new &amp;quot;Notebook&amp;quot; layout, alongside a new Table widget.&lt;/p&gt;
&lt;p&gt;The Notebook layout is designed to allow users to create Dashboards structured like a Notebook (most often seen with the likes of &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter Notebooks&lt;/a&gt; or &lt;a href=&quot;https://observablehq.com/&quot;&gt;ObservableHQ&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Here we will deepdive into the Notebook layout, and show how, alongside our new &lt;strong&gt;Markdown Node&lt;/strong&gt; (&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-markdown.html&quot;&gt;docs&lt;/a&gt;), &lt;strong&gt;Table Node&lt;/strong&gt; (&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-table.html&quot;&gt;docs&lt;/a&gt;) and others, it&#39;s becoming easier to create dynamic and interactive Dashboards.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: If you&#39;re not familiar with Markdown, it&#39;s a simple markup language that allows you to format text. You can learn more about it &lt;a href=&quot;https://www.markdownguide.org/cheat-sheet/&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;dashboard-hierarchy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/#dashboard-hierarchy&quot;&gt;Dashboard Hierarchy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a quick introductory note ahead of our below guide, each Dashboard is structured accordingly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Widget&lt;/strong&gt;: An individual functional block, e.g. button, chart, slider&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group&lt;/strong&gt;: A collection of widgets that render together&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Page&lt;/strong&gt;: A single page/tab in your Dashboard. Each page can have it&#39;s own Layout, in this case we&#39;ll use &amp;quot;Notebook&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI&lt;/strong&gt;: Contains a collection of pages, deployed from Node-RED, provides the basic side navigation to switch between Pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-a-notebook&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/#building-a-notebook&quot;&gt;Building a Notebook&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Example Notebook created in Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/db-notebook-example.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To get started, drop your first widget (in this case, we&#39;ll add a &lt;code&gt;ui-markdown&lt;/code&gt;) onto the Node-RED canvas. This in turn will prompt us to create our first Group/Page/Dashboard which we can name and configure accordingly.&lt;/p&gt;
&lt;p&gt;Let&#39;s add the following Markdown to our first widget:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-55&quot;&gt;
  &lt;pre class=&quot;language-md&quot;&gt;&lt;code id=&quot;code-55&quot; class=&quot;language-md&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; Markdown Content&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here we can render dynamic Markdown content that is&lt;br /&gt;easily &lt;span class=&quot;token italic&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;styled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;_&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We can inject &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`msg.payload`&lt;/span&gt;. For example, here is a&lt;br /&gt;timestamp updating every second: {{ msg.payload }}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-55&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;The joy of &lt;code&gt;ui-markdown&lt;/code&gt; in Dashboard 2.0 is &lt;em&gt;dynamic&lt;/em&gt; content, i.e. content that can be updated by passing messages to the &lt;code&gt;ui-markdown&lt;/code&gt; node. We can wire an &lt;code&gt;inject&lt;/code&gt; node, set it up to repeat every second, and connect it to &lt;code&gt;ui-markdown&lt;/code&gt;. Now, our Markdown content will automatically update show this value.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot to show how an inject node can drive content of a ui-markdown node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/db-notebook-inject.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Resulting in:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Dynamic markdown with an updating timestamp every 1 second&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/md-timestamp.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;adding-more-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/#adding-more-widgets&quot;&gt;Adding More Widgets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because the Notebook is &lt;em&gt;just&lt;/em&gt; a layout, we can still wire together any of the available widgets and existing nodes and display them accordingly.&lt;/p&gt;
&lt;p&gt;Let&#39;s wire a &lt;code&gt;ui-button&lt;/code&gt;, HTTP Request, and &lt;code&gt;ui-table&lt;/code&gt; node. When we click the button, it will perform the HTTP request, and then render the response in the table.&lt;/p&gt;
&lt;p&gt;For this, we&#39;re going to use the Random Jokes API, and in particular, a call to &lt;code&gt;https://official-joke-api.appspot.com/jokes/ten&lt;/code&gt; which will return 10 random jokes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot showing a simple Button &gt; HTTP Request &gt; Table flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/generate-jokes-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We can also re-order the widgets on the page using the Dashboard 2.0 sidebar (as you could in Dashboard 1.0).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot to show how an inject node can drive content of a ui-markdown node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/db-notebook-order.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The above effort results in the following output in our Notebook:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot to show how an inject node can drive content of a ui-markdown node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/db-notebook-jokes-table.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-else-is-new-in-0.4.0%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/09/dashboard-notebook-layout/#what-else-is-new-in-0.4.0%3F&quot;&gt;What else is new in 0.4.0?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The above demonstrates just a few of the new features in the 0.4.0 Release, but we&#39;ve also added &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/releases/tag/v0.4.0&quot;&gt;other fixes and improvements&lt;/a&gt;. In particular, I want to call out Steve&#39;s great work on implementing custom class injection, the first of our new &lt;a href=&quot;https://dashboard.flowfuse.com/user/dynamic-properties.html&quot;&gt;&amp;quot;Dynamic Properties&amp;quot;&lt;/a&gt;, of which there will be more (e.g. visibility, disabled, etc.) to come.&lt;/p&gt;
&lt;p&gt;As always, thanks for reading and your interested in Dashboard 2.0. If you have any feature requests, bugs/complaints or general feedback, please do reach out, and raise issues on our relevant &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;Dashboard 2.0 Activity Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/4&quot;&gt;Dashboard 2.0 Planning Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/new-starter-tier/</id>
        <title>FlowFuse Cloud Starter package - The easiest way to get started with Node-RED</title>
        <summary>Introducing tiers and pricing changes for FlowFuse Cloud</summary>
        <updated>2023-08-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/new-starter-tier/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;FlowFuse is used by businesses and hobbyists alike. We aim to provide a platform that meets the needs of both, recognizing the importance of hobbyists in the Node-RED community and the long term success of FlowFuse as a company. We want to make it as easy as possible for people to get started on FlowFuse Cloud and help them understand the full value the platform offers. One of the barriers we&#39;ve seen has been the current pricing structure of FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;Since FlowFuse Cloud was introduced there’s been essentially one tier for everyone to adopt. Customers were charged $15 per month for each Node-RED instance managed by the FlowFuse platform, whether running in the cloud or on their own hardware using our Device Agent.&lt;/p&gt;
&lt;p&gt;Today we’re introducing different tiers: Starter and Pro. The Starter tier gives you access to 2 FlowFuse managed Node-RED instances, 2 Node-RED devices, with up to 2 team members - all for a flat rate of $15 per month.&lt;/p&gt;
&lt;p&gt;The new Pro tier unlocks more value to adopt FlowFuse in a professional environment and grow beyond the Starter tier. It’s well suited for teams up to 20 members, and includes increased limits for file storage and persistent context. It also unlocks some key features such as the shared Team Library and Project Nodes, used to seamlessly transport data between instances. Pricing starts at $25 per managed Node-RED instance and $15 per device.&lt;/p&gt;
&lt;p&gt;We will soon be launching our third tier, more targeted at Enterprise users. This tier enhances the compliance capabilities through Single-Sign on (SSO), and provides higher SLA’s for both support and high availability for running Node-RED at scale.&lt;/p&gt;
&lt;p&gt;We expect these layers to fit the customers as they grow in their FlowFuse and Node-RED adoption journey.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;do-you-have-an-overview-of-the-different-tiers%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#do-you-have-an-overview-of-the-different-tiers%3F&quot;&gt;Do you have an overview of the different tiers?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Certainly, an overview of the tiers and prices are available at our &lt;a href=&quot;https://flowfuse.com/pricing/&quot;&gt;pricing page&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-upgrade-from-starter-to-pro-tier%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#how-do-i-upgrade-from-starter-to-pro-tier%3F&quot;&gt;How do I upgrade from Starter to Pro tier?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can update your existing team to either tier via the ‘Change Team Type’ option under Team Settings.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-migrate-my-existing-team-to-the-newly-introduced-starter-package-or-pro-tier%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#how-do-i-migrate-my-existing-team-to-the-newly-introduced-starter-package-or-pro-tier%3F&quot;&gt;How do I migrate my existing team to the newly introduced Starter package or Pro tier?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can update your existing team to either tier via the ‘Change Team Type’ option under Team Settings on the &amp;quot;Danger&amp;quot; tab.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-cancel-the-starter-package%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#how-do-i-cancel-the-starter-package%3F&quot;&gt;How do I cancel the Starter Package?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you have deleted any instances, applications or devices in the team, you can delete the Team itself under the Team Settings section.&lt;/p&gt;
&lt;h3 id=&quot;i%E2%80%99m-self-hosting-flowfuse---do-these-changes-affect-me%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#i%E2%80%99m-self-hosting-flowfuse---do-these-changes-affect-me%3F&quot;&gt;I’m self-hosting FlowFuse - do these changes affect me?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, the new team tiers and pricing are on FlowFuse Cloud only.&lt;/p&gt;
&lt;h3 id=&quot;i%E2%80%99m-using-the-digitalocean%2Faws-marketplace-version---do-these-changes-affect-me%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#i%E2%80%99m-using-the-digitalocean%2Faws-marketplace-version---do-these-changes-affect-me%3F&quot;&gt;I’m using the DigitalOcean/AWS Marketplace version - do these changes affect me?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, the new starter tier is only available on FlowFuse Cloud.&lt;/p&gt;
&lt;h3 id=&quot;anything-else%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/new-starter-tier/#anything-else%3F&quot;&gt;Anything else?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have any further questions, please &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact us&lt;/a&gt; and we’ll be happy to discuss.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/</id>
        <title>FlowFuse 1.11 makes it easier to get started with FlowFuse and Node-RED</title>
        <summary>Our latest release includes a new starter tier for FlowFuse Cloud, Personal Access Tokens for API access and improvements to device management.</summary>
        <updated>2023-08-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 1.11 introduces a new starter tier for FlowFuse Cloud that makes it easier to get started with FlowFuse and Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;new-flowfuse-cloud-starter-tier-%232328&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#new-flowfuse-cloud-starter-tier-%232328&quot;&gt;New FlowFuse Cloud Starter Tier  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2328&quot;&gt;#2328&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is now easier for Node-RED developers to get started with FlowFuse and Node-RED. The new starter tier allows developers to use two Node-RED instances and two remote device deployments. Ideal for creating proof of concepts or running a home automation system with Node-RED.&lt;/p&gt;
&lt;p&gt;FlowFuse provides a cloud hosted version of Node-RED so developers don&#39;t need to worry about Node-RED installation or operation. This makes it a lot easier to get started with Node-RED and easier to maintain a running instance.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-api-access-now-possible-via-personal-access-tokens-%2314&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#flowfuse-api-access-now-possible-via-personal-access-tokens-%2314&quot;&gt;FlowFuse API access now possible via personal access tokens &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/14&quot;&gt;#14&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse APIs are now accessible via personal access tokens (PAT). This makes it possible to create automation scripts that interact with the FlowFuse platform using the API and authenticate the scripts with the PAT.&lt;/p&gt;
&lt;h2 id=&quot;usability-improvements-to-device-management-%232294&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#usability-improvements-to-device-management-%232294&quot;&gt;Usability Improvements to Device Management &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2334&quot;&gt;#2294&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A number of usability improvements have been added to the FlowFuse device management solution to make it more flexible and intuitive to use. These improvements include being able to associate devices at the application level allowing for easier editing of Node-RED instances on edge devices.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-rebranding-%23119&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#flowfuse-rebranding-%23119&quot;&gt;FlowFuse Rebranding &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/1?pane=issue&amp;amp;itemId=34719640&quot;&gt;#119&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Earlier in August, &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/&quot;&gt;FlowForge announced&lt;/a&gt; a change to our company and product name to FlowFuse. Work has begun to change the product branding to FlowFuse. The UI has been rebranded and the remaining points will be changed in the next release.&lt;/p&gt;
&lt;h2 id=&quot;other-new-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#other-new-features&quot;&gt;Other New Features&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Add ability to add a description to an application and display it in the portal &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2279&quot;&gt;#2279&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;UI Improvements to device management &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2427&quot;&gt;#2427&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve landing page for documentation &lt;a href=&quot;https://github.com/FlowFuse/website/issues/842&quot;&gt;#842&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Restructure of user interface navigation &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2474&quot;&gt;#2474&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Device running old snapshot &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/132&quot;&gt;#132&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.11.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowfuse-1-11-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go to the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/aws-marketplace-announce/</id>
        <title>FlowFuse is now available on AWS Marketplace</title>
        <summary>Making is easier to run Node-RED and FlowFuse on AWS Cloud</summary>
        <updated>2023-08-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/aws-marketplace-announce/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Many customers want to run FlowFuse in their own cloud environment, AWS being a great example. Today we&#39;re excited to announce that FlowFuse is now available from the &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-3ycrknfg67rug?sr=0-1&amp;amp;ref_=beagle&amp;amp;applicationId=AWSMPContessa&quot;&gt;AWS Marketplace&lt;/a&gt;. This makes it very easy for customers to install and run Node-RED and FlowFuse within minutes.&lt;/p&gt;
&lt;p&gt;FlowFuse allows organizations to reliably deliver Node-RED applications in a continuous, collaborative and secure manner. Customers running FlowFuse on AWS Cloud will benefit from FlowFuse&#39;s features, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Team collaboration for Node-RED developers, allowing multiple developers to work together on a single Node-RED instance, including the ability to have an audit log of changes.&lt;/li&gt;
&lt;li&gt;DevOps deliver pipelines that support a software development lifecycle for Node-RED development. Pipelines can be setup to establish development, test and production environments for Node-RED instances.&lt;/li&gt;
&lt;li&gt;Snapshot of Node-RED instances to create a version history of changes to Node-RED applications. This also includes the ability to rollback to a previous version of a Node-RED instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse on the AWS Marketplace is available under the Apache License c2.0 open source license. Customers can use FlowFuse free of charge but will need to pay AWS EC2 usage for hosting FlowFuse. FlowFuse offers commercially licensed Premimum and Enterprise tiers that includes enterprise oriented features, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;24/7 technical support&lt;/li&gt;
&lt;li&gt;Single Sign-on&lt;/li&gt;
&lt;li&gt;High Availability for Node-RED applications&lt;/li&gt;
&lt;li&gt;Remote device management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Customers can easily upgrade to the premium or enterprise tier by obtaining a commercial license from FlowFuse. To understand what FlowFuse can do for your use-case, please &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;book a demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;FlowFuse on AWS Marketplace is available &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-3ycrknfg67rug?sr=0-1&amp;amp;ref_=beagle&amp;amp;applicationId=AWSMPContessa&quot;&gt;immediately&lt;/a&gt;. Please refer to our &lt;a href=&quot;https://flowfuse.com/docs/install/docker/aws-marketplace/#installing-flowfuse-from-aws-market-place&quot;&gt;documentation&lt;/a&gt; and give it a try and let us know what you think.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/open-source-is-a-tier-not-competition/</id>
        <title>Our Open Source offering is a tier, not our competition</title>
        <summary>Discover the perspective on open source as a valuable tier, not competition.</summary>
        <updated>2023-08-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/open-source-is-a-tier-not-competition/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;More than once we’ve been in discussion with prospective customers on what tier
is the right tier for their current Node-RED adoption. The question is likely to
come up &amp;quot;Why wouldn&#39;t we just use the open source version of FlowFuse?&amp;quot;. The
implicit discussion created is one that is alike the question:
“Why wouldn’t we go with your competition?”. For FlowFuse, and most other open-core
companies like us, the open licensed and free to use core is tier, not competition.&lt;/p&gt;
&lt;p&gt;In the traditional sense, the prospective customer is right. By the definition,
a customer &lt;strong&gt;buys&lt;/strong&gt; goods or services by exchanging it for &lt;strong&gt;money&lt;/strong&gt;. For
FlowFuse’s open-source edition, which is free as in beer and free as in speech,
no money changes hands. It can be installed and run by anyone. Once the software
is being installed and used, we consider we&#39;ve gained a new customer.
There’s an agreement in place, the Apache 2.0 license, and value is obtained by
the customer. The only missing component compared to an ‘ordinary’ sale is the lack
of money from the customer to FlowFuse. The fact that no monetary value is exchanged,
like the situation where a customer picks the competitor, doesn’t make the open
source tier competition. It is just a free tier.&lt;/p&gt;
&lt;p&gt;Another reason it&#39;s really a tier is that the core of the product is the same. In
many open-core products, the path to upgrade from the open source license product to
the paid tier is much alike customers are used to on SaaS models. In the reals of
self-managed software that&#39;s mostly uploading a license and  at times a few configuration
steps.&lt;/p&gt;
&lt;p&gt;Furthermore, the open tier is a tier as the customer choses to not adopt all
capabilities. They&#39;re leaving value on the table. Either this is because it&#39;s not
quite clear what the value is or if  the higher tiers provides
enough business value to warrant the expense. Or the adoption journey for the
customer doesn&#39;t yet require the full featured tiers.&lt;/p&gt;
&lt;p&gt;What’s unique about open source software, is that customers can exchange value
towards the company and community building the software in other forms: by
opening issues, updating documentation, advocating for the OSS variant, among
other ways. While this is not &lt;strong&gt;money&lt;/strong&gt;, it is significant for a young company
like FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;challenges-with-a-open-core-free-tier&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/open-source-is-a-tier-not-competition/#challenges-with-a-open-core-free-tier&quot;&gt;Challenges with a open core free tier&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s not to say that an open source tier is a silver bullet for a company. For
one, it&#39;s hard to track how many users a software package has, and who these users
are. For example; FlowFuse has &lt;a href=&quot;https://flowfuse.com/docs/admin/telemetry/#usage-telemetry&quot;&gt;Telemetry&lt;/a&gt;,
though it can be turned off. Nor do we know who hosts this software.&lt;/p&gt;
&lt;p&gt;Another challenge is around product and feature packaging. At FlowFuse and other open core companies it&#39;s
uncommon to move features from the open tier to paid tier only. If this choice has
been made it&#39;s a done deal, even when the product team got it wrong. Usually the
initial thoughts are therefor to move all features into the paid tiers. However,
this hampers long term growth as adoption of paid features are adopted later or
not at all. We follow the
&lt;a href=&quot;https://opencoreventures.com/blog/2023-01-open-core-standard-pricing-model&quot;&gt;Open-Core buyer based model&lt;/a&gt;
to segregate the value, about which I&#39;ll write a post next time.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@matthardy&quot;&gt;Matt Hardy&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/</id>
        <title>FlowForge is now FlowFuse</title>
        <summary>New identity but same vision for industrial data integration</summary>
        <updated>2023-08-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/flowforge-is-now-flowfuse/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;We are happy to announce that FlowForge is changing its name to FlowFuse. Changing our corporate identity wasn’t our top priority but a recent trademark challenge has promoted us to create a new brand for our company.&lt;/p&gt;
&lt;p&gt;We believe that this new name better reflects our core mission and aspirations. Just as electricity fuses elements to create energy, the FlowFuse platform fuses together data, ideas, processes, and technologies to generate a powerful force of innovation and transformation.&lt;/p&gt;
&lt;p&gt;Selecting a new name for a company or product is never easy. Some of the requirements we set for a new name were: 1) it should be reasonably close to FlowForge so it will be easier to transition the brand identity, 2) it should even better reflect our mission, and 3) keeping the FF acronym will help with environment variable prefixes :-). I think we have accomplished all the above and am delighted to move forward as FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What to Expect Next&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our team is heads down building a platform to allow organizations to reliably deliver Node-RED applications in a continuous, collaborative, and secure manner. We&#39;ll continue to release regular updates packed with new features and enhancements that keeps moving us towards this goal.&lt;/p&gt;
&lt;p&gt;A complete rebranding is a big piece of work - today marks the start of a process as we introduce the new FlowFuse name and updated &lt;a href=&quot;https://flowfuse.com/&quot;&gt;website&lt;/a&gt;. Over the next number of days and weeks we&#39;ll continue to roll this change out, including our social media accounts and other accounts. The product branding will be changed over the next couple of releases, including FlowForge Cloud and FlowForge open source edition. The underlying software will be the as-if you’re running the next FlowForge release, though now called FlowFuse. We&#39;ll share more technical details of this when any changes are made.&lt;/p&gt;
&lt;p&gt;We are excited by the future FlowFuse presents to our customers and the industry. Node-RED and FlowFuse is a powerful combination that gives access to industrial data to transform organizations and drive forward innovation across industries. Join us as we continue our journey.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/dashboard-community-update/</id>
        <title>Dashboard 2.0 - Community Update</title>
        <summary>Our latest Community Update for Dashboard 2.0, including the latest new widgets, fixes and updates on what&#39;s next.</summary>
        <updated>2023-08-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/dashboard-community-update/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the latest Node-RED Dashboard 2.0 update. We&#39;ve added lots of new widgets, cleaned up compatibility issues alongside Dashboard 1.0 and made strides to improve the events system linking the Node-RED editor with the Dashboard.&lt;/p&gt;
&lt;p&gt;I firstly need to begin with a  &lt;em&gt;&amp;quot;Thank You&amp;quot;&lt;/em&gt; to the dozens of pre-alpha users we&#39;ve had so far. Thanks for being patient whilst we&#39;re shipping fast and breaking things. We&#39;ve had some great feedback, and we&#39;re working hard to implement is as best as possible.&lt;/p&gt;
&lt;p&gt;With all of the changes we&#39;ve been making, we&#39;ve also made the decision to jump to minor version numbers, and so, &lt;strong&gt;0.1.0 is available now&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Below you&#39;ll find a summary of the changes we&#39;ve made since our &lt;a href=&quot;https://flowfuse.com/blog/2023/07/dashboard-0-1-release/&quot;&gt;last community update&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;new-widgets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#new-widgets&quot;&gt;New Widgets&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;template-(docs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#template-(docs)&quot;&gt;Template (&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-template.html&quot; target=&quot;_blank&quot;&gt;docs&lt;/a&gt;)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Steve has been doing some incredible work on the new &lt;code&gt;ui-template&lt;/code&gt; widget. This widget allows you to create your own custom components using raw HTML, but also works with any of the components in the &lt;a href=&quot;https://vuetifyjs.com/en/components/all/&quot;&gt;Vuetify&lt;/a&gt; component library. It&#39;s a powerful tool that will enable users to be creative with their own widgets that are not currently available with the standard set of widgets.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Examples of ui-template&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://dashboard.flowfuse.com/images/node-examples/ui-template.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The Template node also provides access to two built-in functions that can be used to send data back to Node-RED:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;send(msg)&lt;/strong&gt;: Outputs a message (defined by the input to this function call) from this node in the Node-RED flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;submit()&lt;/strong&gt;: Send a &lt;code&gt;FormData&lt;/code&gt; object when attached to a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element. The created object will consist of the &lt;code&gt;name&lt;/code&gt; attributes for each form element, corresponding to their respective &lt;code&gt;value&lt;/code&gt; attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;toggle-switch-(docs)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#toggle-switch-(docs)&quot;&gt;Toggle Switch (&lt;a href=&quot;https://dashboard.flowfuse.com/nodes/widgets/ui-switch.html&quot; target=&quot;_blank&quot;&gt;docs&lt;/a&gt;)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Examples of ui-switch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://dashboard.flowfuse.com/images/node-examples/ui-switch.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Adds a toggle switch to the user interface that can be rendered with a label, and traditional toggle switch, or, as in Dashboard 1.0, can be a square element with an icon &amp;amp; color provided.&lt;/p&gt;
&lt;h2 id=&quot;fixes-%26-other-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#fixes-%26-other-changes&quot;&gt;Fixes &amp;amp; Other Changes&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;sidebar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#sidebar&quot;&gt;Sidebar&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As requested on multiple occasions by the community when we released v0.0.4 of Dashboard 2.0, we&#39;ve now added a side menu, as per Dashboard 1.0. Currently, this &lt;em&gt;just&lt;/em&gt; provides a link to the Dashboard UI, but gives us a canvas on which to expand functionality in the future.&lt;/p&gt;
&lt;h3 id=&quot;improved-events-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#improved-events-system&quot;&gt;Improved Events System&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ve re-structured the hierarchy of the events system to make it more streamlined. Now, the &lt;code&gt;ui-base&lt;/code&gt; manages comms via single channels dedicated to each event type, and the widget&#39;s ID is then used as a topic. Previously, we had a separate channel for each &lt;code&gt;action:id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in learning more about our events architecture, you can read about it &lt;a href=&quot;https://dashboard.flowfuse.com/contributing/guides/events.html&quot;&gt;here&lt;/a&gt; in the docs.&lt;/p&gt;
&lt;h3 id=&quot;documentation-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#documentation-updates&quot;&gt;Documentation Updates&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s not glamorous, but it&#39;s important. We&#39;ve made sure that all documentation and help text inside Node-RED is fully up to date for the Dashboard 2.0 nodes. We&#39;ve also include rendered examples for all widgets in our &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;online documentation&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;We&#39;ve also made sure that any legacy options that had been transferred over from Dashboard 1.0 that haven&#39;t been fully implemented yet are temporarily hidden. This means, any options you&#39;re seeing, &lt;em&gt;should&lt;/em&gt; be working. If they&#39;re not - it&#39;s a bug.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We have a lot of things to keep us busy, we are documenting them all in GitHub, and have made public our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/15/views/1&quot;&gt;planning board&lt;/a&gt;. You can see what we&#39;re working on, what&#39;s coming up next, and what we&#39;ve got planned for the future.&lt;/p&gt;
&lt;p&gt;As always, we&#39;re open to ideas, feedback &amp;amp; contributions. If you&#39;d like to get involved, please check out our GitHub Repository &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/dashboard-community-update/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;d like to be paid to directly contribute to Dashboard 2.0, we are hiring for a 2-3 month position to do just that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/</id>
        <title>Why the Automation Pyramid blocks digital transformation - The Role of Unified Namespace</title>
        <summary>A Critical Examination of the Automation Pyramid&#39;s Obstruction to Digital Transformation</summary>
        <updated>2023-08-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;A few years ago, I wrote an &lt;a href=&quot;https://www.linkedin.com/pulse/iiot-circle-marian-raphael-demme/&quot;&gt;article&lt;/a&gt;, in German, detailing my understanding of how the Automation Pyramid, a widely adopted reference model for the IT landscape of manufacturing firms, is essentially hindering digital transformation. Now, as conversations around the Unified Namespace (UNS) and particular frameworks continue to evolve, I revisit my earlier notions, review the latest updates to reference frameworks, and update my article.&lt;/p&gt;
&lt;h2 id=&quot;the-pyramid%E2%80%99s-dilemma&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#the-pyramid%E2%80%99s-dilemma&quot;&gt;The Pyramid’s Dilemma&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Automation Pyramid is grounded in the standard &lt;a href=&quot;https://www.isa.org/products/ansi-isa-95-00-01-2010-iec-62264-1-mod-enterprise&quot;&gt;ISA-95&lt;/a&gt;, which aligns with &lt;a href=&quot;https://www.iso.org/standard/57308.html&quot;&gt;IEC 62264&lt;/a&gt; and &lt;a href=&quot;https://www.beuth.de/en/standard/din-en-62264-1/207270059&quot;&gt;DIN EN 62264&lt;/a&gt;. It delineates the functional hierarchy within a manufacturing enterprise. Over 25 variations of the Automation Pyramid exist in academic literature, all of them fundamentally mapping to the same core concept, tracing back to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Computer-integrated_manufacturing&quot;&gt;Computer-integrated manufacturing&lt;/a&gt; (CIM)-Pyramid of the 1970s. Although ISA-95 does not explicitly refer to a pyramid, it introduces five functional hierarchical levels often visualized as a pyramid.&lt;/p&gt;
&lt;h4 id=&quot;isa-95---visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#isa-95---visualization&quot;&gt;ISA-95 - Visualization&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;ISA95&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ISA95.svg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;automation-pyramid---visualization&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#automation-pyramid---visualization&quot;&gt;Automation Pyramid - Visualization&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Automation Pyramid&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/Automation-Pyramid.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Source: Katti, Badarinath. (2020). Ontology-Based Approach to Decentralized Production Control in the Context of Cloud Manufacturing Execution Systems. 10.13140/RG.2.2.11486.46402.&lt;/p&gt;
&lt;p&gt;A notable critique of ISA-95 is the absence of some operational functions and hierarchical levels commonly seen in manufacturing, leading to a rigidity that limits its applicability. This inflexibility has been acknowledged in a more recent framework, called the &lt;a href=&quot;https://www.isa.org/intech-home/2019/march-april/features/rami-4-0-reference-architectural-model-for-industr&quot;&gt;&amp;quot;Reference Architectural Model Industry 4.0&amp;quot;&lt;/a&gt; RAMI 4.0 (&lt;a href=&quot;https://www.beuth.de/en/norm/pd-iec-pas-63088/272832590&quot;&gt;IEC PAS 63088&lt;/a&gt;). As a result, the authors&#39; introduced a &lt;a href=&quot;https://syc-se.iec.ch/wp-content/uploads/2019/10/Reference_Architecture_final.pdf&quot;&gt;&amp;quot;Smart Grid Architecture Model&amp;quot;&lt;/a&gt; (SGAM) with three primary dimensions: Life Cycle &amp;amp; Value Stream (&lt;a href=&quot;https://www.vde-verlag.de/iec-standards/248992/iec-62890-2020.html&quot;&gt;IEC 62890&lt;/a&gt;), Hierarchy Levels (&lt;a href=&quot;https://www.iso.org/standard/57308.html&quot;&gt;IEC 62264&lt;/a&gt; and &lt;a href=&quot;https://www.vde-verlag.de/iec-standards/216764/iec-61512-4-2009.html&quot;&gt;IEC 61512&lt;/a&gt;), and six main layers displaying the functional architecture of the asset and the separation into physical and digital world.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;RAMI4.0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/RAMI40.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;However, my primary critique revolves around another issue – the structure and proposed communication methodology. Models based on layers, where each tier represents a functional area and could be covered by one or more applications, almost always lead to three fundamental problems:&lt;/p&gt;
&lt;h3 id=&quot;problem-1%3A-information-loss-and-transaction-costs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#problem-1%3A-information-loss-and-transaction-costs&quot;&gt;Problem 1: Information Loss and Transaction Costs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the traditional model, data collection flows upward from Levels 0 to 4, while planning goes downward from Level 4 to 0. Information traversing from Level 0 to Level 4 has to pass through at least four stages. Despite the theoretical lossless transmission of information, the practical scenario inevitably results in some degree of information loss between levels. The result is that the original information from Level 0 arrives at Level 4 late, altered, or not at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; In a manufacturing plant, multiple sensors at Level 1 detect a sudden event. By the time this information passes through intermediary layers (e.g. PLC, SCADA, MES) to reach Level 4 where a planning decision can be made, it is delayed and distorted due to the multiple transitions. The factory might suffer damage before proper actions are taken because the original data didn&#39;t arrive on time or at all.&lt;/p&gt;
&lt;h3 id=&quot;problem-2%3A-the-expense-of-one-to-one-connections&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#problem-2%3A-the-expense-of-one-to-one-connections&quot;&gt;Problem 2: The Expense of One-to-One Connections&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Automation Pyramid is based on different layers. Consequently, one-to-one connections between IT systems become a necessity for data transfer between levels. For example, Level 3 IT systems need at least two connections to the adjacent levels. This can lead to thousands of one-to-one interfaces between IT systems, incurring exorbitant costs for projects and maintenance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; In a semiconductor company, the Manufacturing Execution System (MES) serves as a critical intermediary in the Automation Pyramid. It must be integrated both with PLCs at the lower level for real-time control and with the ERP system at the higher level for business planning. This complex integration leads to the creation of numerous one-to-one connections. Furthermore, in implementing Industry 4.0 use cases like analytical applications, MES data is often required, creating even more connections. The multitude of connections complicates the system, making changes extremely difficult and maintenance intensive. This inflexibility becomes a barrier to adaptability and growth, hindering the efficient digital transformation of the manufacturing process.&lt;/p&gt;
&lt;h3 id=&quot;problem-3%3A-ai&#39;s-dependence-on-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#problem-3%3A-ai&#39;s-dependence-on-data&quot;&gt;Problem 3: AI&#39;s Dependence on Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Artificial intelligence (AI) requires extensive, well-organized data. Given the current architecture, data would have to be  collected and prepared from case to case for each individual system and level. This would invariably lead to numerous new one-to-one connections, offering no flexibility. Hence, AI and the Automation Pyramid can only collaborate in a significantly restricted manner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A car manufacturing firm aims to leverage a neural network for predictive maintenance. Within the constraints of the existing Automation Pyramid&#39;s architecture, the positioning for such an application is nonexistent. To train the neural network and subsequently analyse the data, a consolidation of varying hierarchical data is essential, such as sensory input, maintenance records, production scheduling plans, etc. Under the current architecture, the introduction of this application precipitates the creation of a multitude of new one-to-one connections. Consequently, it underscores the pressing need to rethink the structural paradigms.&lt;/p&gt;
&lt;h2 id=&quot;iiot-circle-and-unified-namespace&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#iiot-circle-and-unified-namespace&quot;&gt;IIoT Circle and Unified Namespace&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To overcome the limitations of traditional industrial data architecture, a paradigm shift towards a modern distributed architecture is necessary. Rather than allowing data to exist in silos within and across layers of the technology stack, data should be made accessible in a unified manner, creating a single, centralized repository. This approach facilitates a single centralized source for all enterprise systems to access the required data for their operations. This framework, which I have been calling the IIoT Circle, modernizes the original idea of the Automation Pyramid. A &amp;quot;Unified Namespace&amp;quot; operates as the core element that processes, and permits data streams to be loaded and exported from other systems. All other applications communicate exclusively through the Unified Namespace, requiring only a single interface to be maintained per application.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;IToT Circle Image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/IIoT-Circle.svg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In essence, Unified Namespace serves as the main data exchange hub within an organization. It structures, organizes, and maintains a real-time flow of data from a variety of sources, becoming the indisputable source of truth across the business. It simplifies data integration, eliminating the frequently convoluted, layered approach of traditional data systems.&lt;/p&gt;
&lt;h3 id=&quot;single-source-of-truth&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#single-source-of-truth&quot;&gt;Single Source of Truth&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Unified Namespace breaks down the linear and deterministic data structure, which create data silos restricted to their specific systems. Instead, Unified Namespace centralizes data from across the entire organization. This results in a &#39;single source of truth&#39; - a consolidated, current, and comprehensive overview of the organization&#39;s data.&lt;/p&gt;
&lt;h3 id=&quot;the-organizational-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#the-organizational-structure&quot;&gt;The Organizational Structure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unified Namespace organizes data using a semantic hierarchy, similar to a meticulously arranged file share system. It can use the &lt;a href=&quot;https://www.isa.org/products/ansi-isa-95-00-02-2018-enterprise-control-system-i&quot;&gt;ISA-95 part 2&lt;/a&gt; or the RAMI 4.0 Hierarchy Level standards to structure the hierarchy. This data organization facilitates navigation, management, and decision-making.&lt;/p&gt;
&lt;h3 id=&quot;the-pub-sub-approach&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#the-pub-sub-approach&quot;&gt;The Pub-Sub Approach&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Publish-Subscribe (Pub-Sub) model facilitates communication that decouples the sender (publisher) from the receiver (subscriber), providing an efficient communication protocol to avoid one-to-one connections. It offers flexibility and scalability as it allows for one-to-many and many-to-one communications, enabling data to flow freely between systems.&lt;/p&gt;
&lt;h2 id=&quot;a-necessity-for-open-source&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#a-necessity-for-open-source&quot;&gt;A Necessity for Open Source&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Moreover, in this discourse on the Unified Namespace, we cannot overlook the role of open-source. Owning foundational digital services, such as the Unified Namespace, is a necessity for any corporation embarking on its digital transformation journey. This ownership provides a solid foundation, allowing companies to chart their destinies. To avoid the constraining bounds of vendor lock-in, which can significantly limit a company&#39;s digital capabilities; open-source or self-developed software offers the best recourse. By its nature, open-source promotes transparency, collaboration, and freedom of use. These aspects are fundamental to fostering innovation and continuous improvement. As exemplified by the &lt;a href=&quot;https://flowfuse.com/blog/2023/02/ming-blog/&quot;&gt;MING Stack&lt;/a&gt;, open source software can and should be incorporated into every level of the hierarchy.&lt;/p&gt;
&lt;h2 id=&quot;summary-%E2%80%93-advancing-current-standards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/isa-95-automation-pyramid-to-unified-namespace/#summary-%E2%80%93-advancing-current-standards&quot;&gt;Summary – Advancing Current Standards&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The lag of standards behind the latest innovation is an open secret, a problem rooted in the nature and development of these standards. However, maintaining and updating these standards remains crucial as many people adhere to them.&lt;/p&gt;
&lt;p&gt;ISA-95 Part 6 mentions a Messaging Service Model (MSM) and proposes a &amp;quot;publish-subscribe&amp;quot; model as an option for transactions. This is a great step in the right direction. My recommendation for ISA-95 is to further develop Part 6 to clearly delineate the implementation pattern of the Unified Namespace. Additionally, ISA-95 Part 1 should make explicit references to the communication pattern detailed in Part 6 and transition from a layer model to a cycle, with the Unified Namespace as an integral part of the framework.&lt;/p&gt;
&lt;p&gt;RAMI 4.0&#39;s Communication Layer is rather abstract. It suggests the use of OPC-UA for everything in manufacturing, from &amp;quot;Product&amp;quot; to &amp;quot;Work Center&amp;quot;. For &amp;quot;Enterprise&amp;quot; and &amp;quot;Connected World&amp;quot;, it states &amp;quot;still undecided&amp;quot;. My improvement suggestion is to define the &amp;quot;Communication Layer&amp;quot; new and to be more technology-agnostic. Be more explicit about what needs to be done and more flexible about how to do it.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/community-news-08/</id>
        <title>Community News August 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-08-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/community-news-08/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for August 2023, a monthly roundup of what’s been happening with FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;new-release&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#new-release&quot;&gt;New Release&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last week we released FlowFuse 1.10, featuring improvements to our device management solutions and the new ability to import environment variable templates. Read about the details of FlowFuse 1.10 in our &lt;a href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/&quot;&gt;release announcement&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;getting-started-with-opc-ua-and-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#getting-started-with-opc-ua-and-node-red&quot;&gt;Getting Started with OPC-UA and Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OPC-UA is a popular communication protocol used to communicate industrial data between different types of hardware and software. Our next webinar show how to use Node-RED to create an OPC-UA client that can read OPC data and visualize the data in Node-RED. We are glad to welcome Mika Karaila, Research Director @ Valmet Automation and creator of the OPC-UA nodes, as our webinar speaker.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/getting-started-opcua-node-red/&quot;&gt;Sign-up today&lt;/a&gt; to join us on July 27.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Our developer advocate, Richard Meyer, published a series of articles on OPC-UA:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part 1: &lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/&quot;&gt;How to Deploy a Basic OPC-UA Server in Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 2: &lt;a href=&quot;https://flowfuse.com/node-red/protocol/opc-ua/&quot;&gt;How to Build a Secure OPC-UA Server for PLCs in Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 3: &lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/&quot;&gt;How to Build an OPC UA Client Dashboard in Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/07/dashboard-0-1-release/&quot;&gt;First Pre-Alpha Release of the new Node-RED Dashboard&lt;/a&gt; - update on FlowFuse&#39;s work to develop the next generation of Node-RED dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/&quot;&gt;How to add images to Node-RED dashboards when using FlowFuse&lt;/a&gt; - some tips on how to add images to a dashboard when running Node-RED instances in a docker environment, like FlowFuse.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/&quot;&gt;Creating a Historical Data Dashboard with InfluxDB and Node-RED&lt;/a&gt; - an in-depth article on how to store historical data in InfluxDB that can be visualize with Node-RED dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Featured Node&lt;/strong&gt;: &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-buffer-parser&quot;&gt;Buffer Parser&lt;/a&gt; - a really useful node for parsing buffers/arrays that are common in industrial data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/community-news-08/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/08/flowforge-1-10-release/</id>
        <title>FlowFuse 1.10 Release Now Available</title>
        <summary>New FlowFuse 1.10 also includes improvements to device management and importing environment variable templates.</summary>
        <updated>2023-08-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/08/flowforge-1-10-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 1.10 release includes improvements to device management and importing environment variable templates.&lt;/p&gt;
&lt;h2 id=&quot;import-environment-variable-templates-%232372&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#import-environment-variable-templates-%232372&quot;&gt;Import Environment Variable Templates  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2372&quot;&gt;#2372&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse 1.10 now allows users to import environment variable templates. This makes it much easier and less error prone to maintain and add new environment variables to Node-RED instances running on FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;devops-pipelines-now-can-include-devices-%232243&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#devops-pipelines-now-can-include-devices-%232243&quot;&gt;DevOps Pipelines now can include devices &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2243&quot;&gt;#2243&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DevOps pipelines have proven very popular for creating dev/test/production environments for Node-RED flow development. Now, devices can be associated with a pipeline so when a snapshot is created it can be pushed to all the devices associated with the pipeline.  This will improve the overall quality and reliability of Node-RED development for remote devices.&lt;/p&gt;
&lt;h2 id=&quot;devices-can-now-access-the-team-library-%232294&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#devices-can-now-access-the-team-library-%232294&quot;&gt;Devices can now access the team library &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2294&quot;&gt;#2294&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Team libraries allow Node-RED development team to share common flows and nodes through a shared library. Until the 1.10 release, Node-RED running remotely on a device did not have access to the team library. This limitation is now removed so device development can benefit from reusing standard flows.&lt;/p&gt;
&lt;h2 id=&quot;other-new-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#other-new-features&quot;&gt;Other New Features&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Add description of device type field  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2428&quot;&gt;#2428&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve reliability of device editor &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2483&quot;&gt;#2483&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve error feedback from device editor tunnel &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2473&quot;&gt;#2473&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Improve visualization of Last Seen &amp;amp; Last Known with large amounts of devices. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2380&quot;&gt;#2380&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fix billing information error in FlowFuse Cloud &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2416&quot;&gt;#2416&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fix T&amp;amp;C checkbox on sign-up page &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2419&quot;&gt;#2419&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;community-contributions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#community-contributions&quot;&gt;Community Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to our community members for their contributions to this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dfulgham&quot;&gt;dfulgham&lt;/a&gt; - Added support for annotation substitutions &lt;a href=&quot;https://github.com/FlowFuse/flowforge-driver-k8s/pull/95&quot;&gt;#95&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/elenaviter&quot;&gt;elanaviter&lt;/a&gt; - Editors: allow optional service account linkage &lt;a href=&quot;https://github.com/FlowFuse/flowforge-driver-k8s/pull/92&quot;&gt;#92&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.10.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/08/flowforge-1-10-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go the the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/</id>
        <title>How to Build an OPC UA Client Dashboard in Node-RED - Part 3</title>
        <summary>Interactive OPC UA Client dashboard that communicates with a 3rd party OPC UA Server</summary>
        <updated>2023-07-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This article is the third and final part of our OPC UA content series. In the &lt;a href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/&quot;&gt;first article&lt;/a&gt;, we cover some OPC UA fundamentals and walk through an example OPC UA Server flow. In the &lt;a href=&quot;https://flowfuse.com/node-red/protocol/opc-ua/&quot;&gt;second article&lt;/a&gt;, we built a SSL-secured OPC UA server using data from an Allen Bradley PLC as a source.
In this article, we show how to build an OPC Client in Node-RED that communicates with a 3rd party OPC UA Server and utilizes an interactive dashboard.&lt;/p&gt;
&lt;p&gt;This article will requires the &lt;a href=&quot;https://prosysopc.com/products/opc-ua-simulation-server/&quot;&gt;Prosys OPC UA Simulation Server&lt;/a&gt;, an application designed for testing OPC UA client applications and learning the technology.  It’s a free cross-platform application that supports Windows, Linux, and MacOS.  This article will use the Windows version.&lt;/p&gt;
&lt;p&gt;Note: full source code for the OPC Client Dashboard is included at the end of the article.&lt;/p&gt;
&lt;h2 id=&quot;custom-nodes-used-%26-assumptions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#custom-nodes-used-%26-assumptions&quot;&gt;Custom Nodes Used &amp;amp; Assumptions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Several custom nodes are required in order to properly deploy this flow.  For more detailed information on how to install a custom node, follow the instructions from an &lt;a href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/&quot;&gt;earlier article&lt;/a&gt; where the process on installing custom nodes is explained in detail.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;@flowfuse/node-red-dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;node-red-contrib-opcua&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard-2-ui-led&quot;&gt;@flowfuse/node-red-dashboard-2-ui-led&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As this is not a production application, no security will be utilized, and it is assumed that the OPC UA Server is running on the same network as the Node-RED OPC Client.&lt;/p&gt;
&lt;p&gt;Is it also assumed that the end user of this article has familiarization with dashboards.  There are many dashboard basic guides available on our FlowFuse website, For more infomation go to &lt;a href=&quot;https://flowfuse.com/blog/dashboard/&quot;&gt;Node-RED Dashboard 2.0 guides&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;install-and-deploy-the-prosys-opc-ua-simulation-server&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#install-and-deploy-the-prosys-opc-ua-simulation-server&quot;&gt;Install and Deploy the Prosys OPC UA Simulation Server&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Prosys OPC UA Simulation Server is &lt;a href=&quot;https://prosysopc.com/products/opc-ua-simulation-server/evaluate/&quot;&gt;free to download&lt;/a&gt;, but requires a sign-up process.  Download and install the server, then run the application.  Once the application is started, the first thing you should do is go to &lt;code&gt;options -&amp;gt; switch to expert mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will give us access to the address space tab, which we will need to develop our client application in Node-RED.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;expert-mode.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/expert-mode.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;When the application is run, an endpoint url will be displayed on the &lt;code&gt;status&lt;/code&gt; tab, along with an indication that the server is currently running.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opc-endpoint-url.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-endpoint-url.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Copy the connection endpoint, but be warned that you will likely need to replace the computer name (in my case &lt;code&gt;DESKTOP-0K0483A&lt;/code&gt;, with the actual IP address of the machine running the server.  The IP address of the machine on my local network is &lt;code&gt;192.168.0.141&lt;/code&gt;, which changes my UA TCP endpoint address to &lt;code&gt;opc.tcp://192.168.0.141:53530/OPCUA/SimulationServer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now the simulation server is set up and we are ready to start developing the OPC Client application.&lt;/p&gt;
&lt;h2 id=&quot;objectives-of-the-node-red-opc-client-dashboard-application&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#objectives-of-the-node-red-opc-client-dashboard-application&quot;&gt;Objectives of the Node-RED OPC Client Dashboard Application&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal is not to develop a production-level application, rather, it’s to show a variety of features that one can utilize to demonstrate common OPC UA Client application capabilities in Node-RED, while also demonstrating a variety of methods to visualize the results in a dashboard.  There are 4 main objectives of the Node-RED OPC Client Dashboard application. They are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browse hierarchical server address space structure &amp;amp; display on a dashboard&lt;/li&gt;
&lt;li&gt;Read OPC UA values from various namespaces, showing a variety of datatypes and different ways they can be visualized&lt;/li&gt;
&lt;li&gt;Write OPC UA values back to the OPC UA server directly from the OPC UA Client dashboard&lt;/li&gt;
&lt;li&gt;Read alarms &amp;amp; events from the OPC UA Server and display them on the dashboard&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rather than building the flow step-by-step, the flow source code will be presented for each objective, and a the flow will be explained so that it is understood what is happening in each section of code.&lt;/p&gt;
&lt;h2 id=&quot;browse-hierarchical-server-address-space-structure-with-opc-ua-browser-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#browse-hierarchical-server-address-space-structure-with-opc-ua-browser-node&quot;&gt;Browse Hierarchical Server Address Space Structure With OPC UA Browser Node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first flow will browse the hierarchical OPC UA Server address space structure and display it on the dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;image-20230727-085611.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/image-20230727-085611.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can import this flow into Node-RED using the code below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-166&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow166 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Browse Hierarchical Address Space Structure &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;78a012e5db377fd9&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:139,&#92;&quot;w&#92;&quot;:1172,&#92;&quot;h&#92;&quot;:422},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Base Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b17b2da2b942bb4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.Simulation.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;335878527020598c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;52dd2e5dcddad58f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b208f2e8cba6205&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get StaticData Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29437ca7222d9a64&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.AnalogItemArrays.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;157322c9c360446d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.StaticArrayVariables.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a5acdccfd2033aec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Object&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.MyDevice.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;78a012e5db377fd9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyObjects Object Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac95bd0e2b304eec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;de21b7ad98a05833&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store &amp;amp; Parse nodeId &amp;amp; browseName&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Global Address Space Folder Browse&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 3&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 5&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder-arrow-down&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;p&amp;gt;Namespace 6&amp;lt;/p&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1130,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;78a012e5db377fd9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice&#92;&quot;,&#92;&quot;order&#92;&quot;:6,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.56.1:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot; Address Space Folder Structure&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/opcua&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow166.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-166&#39;) })&lt;/script&gt;
&lt;p&gt;To understand what is going on in this flow, we must refer back to the OPC UA Simulation Server &lt;code&gt;Address Space&lt;/code&gt; tab.&lt;/p&gt;
&lt;p&gt;When we browse the OPC Server base folder structure in Node-RED, we will be browsing everything included under the &lt;code&gt;Objects&lt;/code&gt; tree.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;address-space.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/address-space.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
In our flow, we get the base folder structure by using an OPC-UA Browser node, as shown, with an endpoint that points to our OPC UA Server endpoint url we grabbed earlier in this article.  It is also worth noting we leave the &lt;code&gt;Topic&lt;/code&gt; blank.  By doing this, we will browse the entire folder structure by default.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;image-20230727-090252.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/image-20230727-090252.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
The configuration of the endpoint properties includes no security credentials, as shown below.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;endpoint-configure.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/endpoint-configure.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Using the output of a debug node, we get from the OPC UA Browser yield a payload with an array of 5 objects.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;address-debug.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/address-debug.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Each object returned represents the 5 objects that are in our OPC UA Server Objects tree.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;browse-payload-1.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/browse-payload-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;However, of those 5 objects, only 3 of them are folders that contain actual OPC values.  &lt;code&gt;MyObjects&lt;/code&gt;, &lt;code&gt;Simulation&lt;/code&gt;, and &lt;code&gt;StaticData&lt;/code&gt;.  We can ignore &lt;code&gt;Aliases&lt;/code&gt; and &lt;code&gt;Server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;address-space-folders-only.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/address-space-folders-only.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;So looking deeper into the payload of our global browse from the &lt;code&gt;OPC UA Browser node&lt;/code&gt;, we can drill down into the details and see how they correlate with the folders in the server.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;browse-node.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/browse-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;As shown above, element 2 in the array returned from the global browse corresponds to the &lt;code&gt;Simulation&lt;/code&gt; folder.  And we are interested in two important values in this data-structure - the &lt;code&gt;NodeId&lt;/code&gt;, which is topic an OPC Client uses to point specific OPC values, and the &lt;code&gt;browseName&lt;/code&gt;, which is the name we see visually when we try to identify an OPC topic.  We can now use this logic to parse out this useful information using a change node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;simulation-folder.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/simulation-folder.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
This change node is grabbing the &lt;code&gt;nodeId&lt;/code&gt; and &lt;code&gt;browseName&lt;/code&gt; .  The &lt;code&gt;nodeId&lt;/code&gt; is stored in a context variable for later use, while the &lt;code&gt;browseName&lt;/code&gt; is used as the payload to be displayed on our dashboard.&lt;/p&gt;
&lt;p&gt;The rest of the flow follows this same pattern, to end up with a folder structure that we can display on our dashboard that matches the structure on our OPC Server&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;note - to make the flow more manageable, not all browsable folders were included in the dashboard, as this flow is just meant to serve as an example, rather than be a 1:1 copy of everything in the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you deploy the flow and pull up the dashboard, it results in the following output -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;address-space-dashboard.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/address-space-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Showing side-by-side with the server, you can see that we successfully browsed a portion of the address space and displayed the values on the dashboard.  Admittedly, a lot of work for not much pay-off, but it’s a worthwhile exercise in understanding how to browse topics using the &lt;code&gt;OPC UA Browser&lt;/code&gt; node.  The browser node is best used for reading OPC UA values, which will be covered next.&lt;/p&gt;
&lt;h2 id=&quot;read-opc-ua-values-using-opc-ua-browser-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#read-opc-ua-values-using-opc-ua-browser-node&quot;&gt;Read OPC UA Values Using OPC UA Browser Node&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next set of flows read OPC UA values from the server and displays them on the dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;read-opc-values.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/read-opc-values.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
You can import these flows into Node-RED using the code below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-167&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow167 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Browse Hierarchical Address Space Structure &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;78a012e5db377fd9&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:139,&#92;&quot;w&#92;&quot;:1172,&#92;&quot;h&#92;&quot;:422},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Base Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b17b2da2b942bb4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.Simulation.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;335878527020598c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;52dd2e5dcddad58f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b208f2e8cba6205&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get StaticData Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29437ca7222d9a64&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.AnalogItemArrays.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;157322c9c360446d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.StaticArrayVariables.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a5acdccfd2033aec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Object&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.MyDevice.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;78a012e5db377fd9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyObjects Object Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac95bd0e2b304eec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;de21b7ad98a05833&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store &amp;amp; Parse nodeId &amp;amp; browseName&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Global Address Space Folder Browse&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 3&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 5&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder-arrow-down&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;p&amp;gt;Namespace 6&amp;lt;/p&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1130,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;78a012e5db377fd9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice&#92;&quot;,&#92;&quot;order&#92;&quot;:6,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.56.1:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot; Address Space Folder Structure&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/opcua&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Simulation Values &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;9659d40ac9063764&#92;&quot;,&#92;&quot;9f5b597ec8179fb4&#92;&quot;,&#92;&quot;a8d919f497fcff04&#92;&quot;,&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;ec5dca5eb9d4971b&#92;&quot;,&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;4d9b758e39555124&#92;&quot;,&#92;&quot;da468bc150517fa6&#92;&quot;,&#92;&quot;82aa12173dd7bbca&#92;&quot;,&#92;&quot;57d8777e34b55b7b&#92;&quot;,&#92;&quot;10877909d1daf6fe&#92;&quot;,&#92;&quot;c4d4a3b0df372e4c&#92;&quot;,&#92;&quot;b0cf511f824f2a86&#92;&quot;,&#92;&quot;f2efc6b419414c9a&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:599,&#92;&quot;w&#92;&quot;:1372,&#92;&quot;h&#92;&quot;:302},{&#92;&quot;id&#92;&quot;:&#92;&quot;9659d40ac9063764&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ec5dca5eb9d4971b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9f5b597ec8179fb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update Simulation Values @ 1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.Simulation.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9659d40ac9063764&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a8d919f497fcff04&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Simulation Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Counter Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:680,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;10877909d1daf6fe&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec5dca5eb9d4971b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;4d9b758e39555124&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Random Number Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c4d4a3b0df372e4c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Sawtooth Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b0cf511f824f2a86&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d9b758e39555124&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Sawtooth Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2efc6b419414c9a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;da468bc150517fa6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Discard Empty Datasets&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;82aa12173dd7bbca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse Simulation Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;57d8777e34b55b7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;10877909d1daf6fe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Counter&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:3,&#92;&quot;height&#92;&quot;:3,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;15&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:680,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4d4a3b0df372e4c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1350,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b0cf511f824f2a86&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f2efc6b419414c9a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Sinusoid&#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation values&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read StaticData Values &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e998aa804042128b&#92;&quot;,&#92;&quot;6c9b7d4d195a1e9a&#92;&quot;,&#92;&quot;cd097b744d0ec625&#92;&quot;,&#92;&quot;18d21607c87ab153&#92;&quot;,&#92;&quot;7b5143c4960f92a1&#92;&quot;,&#92;&quot;0625b0cf6f546a4a&#92;&quot;,&#92;&quot;9d899fbb4d1648b3&#92;&quot;,&#92;&quot;6e1edc31687dde54&#92;&quot;,&#92;&quot;051e1f282076fed2&#92;&quot;,&#92;&quot;de2a1c3e380f743b&#92;&quot;,&#92;&quot;c74606c48ccf5a40&#92;&quot;,&#92;&quot;053bda13f2a2eabe&#92;&quot;,&#92;&quot;277dcf430dc86996&#92;&quot;,&#92;&quot;d708e6264cec0070&#92;&quot;],&#92;&quot;x&#92;&quot;:84,&#92;&quot;y&#92;&quot;:939,&#92;&quot;w&#92;&quot;:1382,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;e998aa804042128b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b5143c4960f92a1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6c9b7d4d195a1e9a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update AnalogItemArrays Values @ 1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.AnalogItemArrays.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e998aa804042128b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cd097b744d0ec625&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read StaticData Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18d21607c87ab153&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get ByteAnalogItemArray Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$string(payload[0].item.value)&#92;&#92;t&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;277dcf430dc86996&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b5143c4960f92a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;18d21607c87ab153&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0625b0cf6f546a4a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;051e1f282076fed2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9d899fbb4d1648b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update StaticArrayVariables Values @1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.StaticArrayVariables.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0625b0cf6f546a4a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6e1edc31687dde54&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get BooleanArray Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d708e6264cec0070&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;051e1f282076fed2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6e1edc31687dde54&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de2a1c3e380f743b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Discard Empty Datasets&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c74606c48ccf5a40&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse StaticData Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;053bda13f2a2eabe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;277dcf430dc86996&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;ByteAnalogItemArray&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d708e6264cec0070&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;BooleanArray&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData Values&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow167.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-167&#39;) })&lt;/script&gt;
&lt;p&gt;The values are derived from the &lt;code&gt;nodeId&lt;/code&gt; values we stored in memory in our previous flow, via our &lt;code&gt;change&lt;/code&gt; nodes in the previous flow.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;flow-context-nodeid.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-context-nodeid.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
As stated earlier, you reference a OPC UA topic by its &lt;code&gt;nodeId&lt;/code&gt;.  So we will use these node IDs to read actual values from our OPC nodes.&lt;/p&gt;
&lt;p&gt;In our first flow, we want to read the values in the &lt;code&gt;Simulation&lt;/code&gt; folder at a 1 second interval.  So we use an &lt;code&gt;inject&lt;/code&gt; node with a &lt;code&gt;msg.topic&lt;/code&gt; that references the &lt;code&gt;nodeId&lt;/code&gt; corresponding to the &lt;code&gt;Simulation&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;simulation-injection.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/simulation-injection.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
That &lt;code&gt;msg.topic&lt;/code&gt; tells the &lt;code&gt;OPC UA Browser&lt;/code&gt; node what &lt;code&gt;nodeId&lt;/code&gt; to browse.  If we look at the debug output of the browser &lt;code&gt;msg.payload&lt;/code&gt;, we can see that it produces an array of 7 objects, and an empty set array.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;simulation-debug.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/simulation-debug.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
If we allow that empty array to be passed, that means all values will be reset to 0 on each read.  So to prevent that from happening, we use a &lt;code&gt;switch&lt;/code&gt; node to filter out the empty set.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;empty-check.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/empty-check.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Now only non-empty payloads will be passed, preventing the values being reset to 0 on each read.&lt;/p&gt;
&lt;p&gt;Now we can actually read the values.  To do this, we use a &lt;code&gt;change&lt;/code&gt; node again, referencing the non-empty payload and drilling down to the &lt;code&gt;value&lt;/code&gt; that corresponds to the &lt;code&gt;name&lt;/code&gt; of the node we want to read.  In this case, we’re getting the value of the node &lt;code&gt;Counter&lt;/code&gt; located in the &lt;code&gt;Simulation&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;get-counter-value.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/get-counter-value.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Going back to our OPC Server, we can see that exactly where that value is derived below -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;sim-counter-server.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/sim-counter-server.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now we add a &lt;code&gt;gauge&lt;/code&gt; dashboard node to visualize the counter on the dashboard.  In the OPC Server, it is shown that the counter increments in a range of 0-30 in 1 count increments.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;counter-properties.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/counter-propertie.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Now that we’ve gone through the full process of reading an OPC UA value and displaying it on the dashboard, we can apply the same logic other values published by the OPC UA Server, which are repeated in the remaining parts of the flow.&lt;/p&gt;
&lt;p&gt;The end result on the dashboard now looks like this -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opc-read-dashboard.gif&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-read-dashboard.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;write-opc-ua-values-to-server-using-opcua-item-and-opc-ua-client-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#write-opc-ua-values-to-server-using-opcua-item-and-opc-ua-client-nodes&quot;&gt;Write OPC UA Values To Server Using OpcUa-Item and Opc-Ua-Client Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next flow writes OPC UA values to the server using dashboard UI elements.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;write-mydevice.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/write-mydevice.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
You can import this flow into Node-RED using the code below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-168&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow168 = &quot; &#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Mydevices values to OPC UA Server&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;a66583d91b581cd8&#92;&quot;,&#92;&quot;3e8cb6e199012155&#92;&quot;,&#92;&quot;9fa33d1c9c621611&#92;&quot;,&#92;&quot;fb7f57b4da5883ae&#92;&quot;,&#92;&quot;9c5ff104eb9c8b10&#92;&quot;,&#92;&quot;77bcb828bec95336&#92;&quot;,&#92;&quot;afa83dbb46449d4a&#92;&quot;,&#92;&quot;fa08f0ed04296363&#92;&quot;,&#92;&quot;9f591797b56c565d&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:1439,&#92;&quot;w&#92;&quot;:792,&#92;&quot;h&#92;&quot;:182},{&#92;&quot;id&#92;&quot;:&#92;&quot;a66583d91b581cd8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=6;s=MySwitch&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Boolean&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Toggle MySwitch&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3e8cb6e199012155&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3e8cb6e199012155&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Write MySwitch&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9fa33d1c9c621611&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard Input&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb7f57b4da5883ae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=6;s=MyLevel&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Double&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Modify MyLevel&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9c5ff104eb9c8b10&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9c5ff104eb9c8b10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Write MyLevel&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;77bcb828bec95336&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Call OPC UA Item&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;afa83dbb46449d4a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write OPC UA Item to Client&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa08f0ed04296363&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Toggle MySwitch&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;style&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;onvalue&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;onvalueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;onicon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;oncolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offvalue&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;offvalueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;officon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a66583d91b581cd8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9f591797b56c565d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-slider&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Modify MyLevel&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;outs&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;thumbLabel&#92;&quot;:true,&#92;&quot;min&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;step&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fb7f57b4da5883ae&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.56.1:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Status &amp;amp; Control&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/opcua&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow168.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-168&#39;) })&lt;/script&gt;
&lt;p&gt;We have two values to write, a boolean value corresponding to the node object &lt;code&gt;MySwitch&lt;/code&gt;, and an integer value corresponding to the object &lt;code&gt;MyLevel&lt;/code&gt;. Therefore, we will use a toggle switch to toggle the &lt;code&gt;MySwitch&lt;/code&gt;, and a slider to modify &lt;code&gt;MyLevel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There’s no need to modify the toggle switch properties, other than giving it a name.  The slider needs to have the range modified to match the range of the level, which is 0-100%.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;level-range.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/level-range.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
For the &lt;code&gt;OpcUa-Item&lt;/code&gt; nodes, copy the &lt;code&gt;NodeId&lt;/code&gt; corresponding to each device,&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;copy-node-id.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/copy-node-id.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
and paste it into &lt;code&gt;OpcUa-Item&lt;/code&gt; node.  You must also ensure the data-type matches with the value you’re writing to.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opcua-item.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opcua-item.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
The &lt;code&gt;Opc-Ua-Client&lt;/code&gt; needs to have an endpoint and the action changed to &lt;code&gt;WRITE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;client-node.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/client-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
The process is the same for &lt;code&gt;MySwitch&lt;/code&gt; and &lt;code&gt;MyLevel&lt;/code&gt;, the only difference being what &lt;code&gt;NodeId&lt;/code&gt; is referenced in the  &lt;code&gt;OpcUa-Item&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;When deployed, you can confirm values are being written to from the client to the server from the dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opc-write.gif&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-write.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;read-alarms-%26-events-from-opc-ua-server-using-opcua-event-and-opc-ua-client-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#read-alarms-%26-events-from-opc-ua-server-using-opcua-event-and-opc-ua-client-nodes&quot;&gt;Read Alarms &amp;amp; Events from OPC UA Server Using OpcUa-Event and Opc-Ua-Client Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our last flow we’ll show how to read OPC UA Alarms &amp;amp; Events.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opc-event-flow.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-event-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
You can import this flow into Node-RED using the code below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-169&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow169 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Alarms &amp;amp; Events From OPC UA Server&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;90fb4ca64a642edf&#92;&quot;,&#92;&quot;b76f64786bc681c3&#92;&quot;,&#92;&quot;71e24b671bc03fb8&#92;&quot;,&#92;&quot;c7438df35b506470&#92;&quot;,&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;04992b24a3836f19&#92;&quot;,&#92;&quot;325068cb935cd6d1&#92;&quot;,&#92;&quot;5b4d1bd8b342fc05&#92;&quot;,&#92;&quot;ba1ea89438335cb8&#92;&quot;,&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;1e3956200997581f&#92;&quot;,&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;,&#92;&quot;62b2e14ce0429eef&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:1679,&#92;&quot;w&#92;&quot;:1352,&#92;&quot;h&#92;&quot;:282},{&#92;&quot;id&#92;&quot;:&#92;&quot;90fb4ca64a642edf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Call OPC UA Item&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1820,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b76f64786bc681c3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;root&#92;&quot;:&#92;&quot;ns=6;s=MyLevel.Alarm&#92;&quot;,&#92;&quot;activatecustomevent&#92;&quot;:false,&#92;&quot;eventtype&#92;&quot;:&#92;&quot;i=2041&#92;&quot;,&#92;&quot;customeventtype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyLevel Alarms&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c7438df35b506470&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;71e24b671bc03fb8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger Alarm Event Capture&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b76f64786bc681c3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c7438df35b506470&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;events&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyLevel Events&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;04992b24a3836f19&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Text&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Message.text&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;1e3956200997581f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Time&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Time&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;04992b24a3836f19&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Severity&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Severity&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1000,&#92;&quot;y&#92;&quot;:1920,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;62b2e14ce0429eef&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;325068cb935cd6d1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse Event Dataset&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1760,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5b4d1bd8b342fc05&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get OPC Events from Client&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1820,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba1ea89438335cb8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display Events on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:1720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Notification&#92;&quot;,&#92;&quot;x&#92;&quot;:1230,&#92;&quot;y&#92;&quot;:1800,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e3956200997581f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:1840,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event Timestamp&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1280,&#92;&quot;y&#92;&quot;:1880,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;62b2e14ce0429eef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event Severity&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:1920,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.56.1:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Status &amp;amp; Control&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/opcua&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow169.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-169&#39;) })&lt;/script&gt;
&lt;p&gt;We use an inject node to trigger the &lt;code&gt;OpcUa-Event&lt;/code&gt; node.  In the properties of the event node, we get the &lt;code&gt;NodeId&lt;/code&gt; from the &lt;code&gt;MyLevelAlarm&lt;/code&gt; event from the OPC Server -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;mylevel-event.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/mylevel-event.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
And copy that &lt;code&gt;NodeId&lt;/code&gt; into the &lt;code&gt;OpcUa-Event&lt;/code&gt; node.  Event type will be &lt;code&gt;BaseEvent (all)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;event-node-properties.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/event-node-properties.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
In the &lt;code&gt;Opc-Ua-Client&lt;/code&gt; node, we set the &lt;code&gt;Action&lt;/code&gt; to &lt;code&gt;EVENTS&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;client-events.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/client-events.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
If we stick a debug node on the output of the client event, we can see how the OPC Server annunciates events.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;event-debug.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/event-debug.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Every time &lt;code&gt;MyLevel&lt;/code&gt; exceeds certain thresholds (10%, 30%, 70% and 90%) it will flag a &lt;code&gt;Level Exceeded&lt;/code&gt; alarm.   The event is timestamped and assigned a severity level, which we will record and put onto the dashboard.&lt;/p&gt;
&lt;p&gt;To make things simple, we’ll only track the last event.  But in a production system, you’d likely want to store these events in a relational database (historian) to keep an alarm history.  We’ll also include a notification pop-up when an alarm occurs to notify someone monitoring the dashboard a new alarm has occurred.&lt;/p&gt;
&lt;p&gt;Adding alarms and events to our dashboard creates the following result -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img data-zoomable=&quot;&quot; alt=&quot;opc-event.gif&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-event.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;using-flowfuse-to-enhance-your-node-red-application%3A-security%2C-scalability%2C-and-robustness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#using-flowfuse-to-enhance-your-node-red-application%3A-security%2C-scalability%2C-and-robustness&quot;&gt;Using FlowFuse to Enhance Your Node-RED Application: Security, Scalability, and Robustness&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, you&#39;ve successfully built your Node-RED application—congratulations! But now, how do you ensure its security, scalability, and ease of collaboration? What if you want to invite your team to work on the application simultaneously or access it remotely?&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt;, a cloud-based platform designed to add production-grade features to your Node-RED applications. With FlowFuse, you can seamlessly integrate advanced security measures, scale your application as needed, and collaborate effortlessly with your team. It simplifies management and deployment, turning your Node-RED project into a robust, scalable solution.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in learning how to use Node-RED for professional use cases, check out our eBook: &lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;Ultimate Beginner&#39;s Guide to Professionals&lt;/a&gt;. For additional resources, visit our &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/&quot;&gt;Node-RED Learning Resources section&lt;/a&gt;, where you can explore integrations with different protocols, messaging services, databases, hardware, and much more.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-build-a-opc-client-dashboard-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this final article, we went over building a OPC UA Client dashboard that can browse the address space, read values from an OPC Server, write values to an OPC Server, and get events from an OPC Server.&lt;/p&gt;
&lt;p&gt;This flow provides examples that can serve as a foundation for an interactive OPC Client application built in Node-RED.  This now concludes the OPC UA Series.&lt;/p&gt;
&lt;p&gt;full source code for this project -&lt;/p&gt;
&lt;div id=&quot;nr-flow-170&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow170 = &quot; &#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Browse Hierarchical Address Space Structure &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;78a012e5db377fd9&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:139,&#92;&quot;w&#92;&quot;:1172,&#92;&quot;h&#92;&quot;:422},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b17b2da2b942bb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;639da01fc957e547&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;61797eccf2785257&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Base Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b17b2da2b942bb4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d92d940177b6ee3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.Simulation.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;335878527020598c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;68a113d5893b7c01&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d0c969b6a59fac3a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;52dd2e5dcddad58f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;639da01fc957e547&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b208f2e8cba6205&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29437ca7222d9a64&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;e7c55f412ef86543&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49983d5da0958bf2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get StaticData Folder Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.3&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29437ca7222d9a64&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49040d0cf1144f0a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.AnalogItemArrays.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;157322c9c360446d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e7c55f412ef86543&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables Folder&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.StaticData.StaticArrayVariables.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[6].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:860,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a5acdccfd2033aec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de21b7ad98a05833&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Object&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;Objects.MyObjects.MyDevice.nodeId&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.nodeId&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.browseName.name&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;78a012e5db377fd9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d56e9a431c21a3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyObjects Object Structure&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.MyObjects.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ac95bd0e2b304eec&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac95bd0e2b304eec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;de21b7ad98a05833&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6fdabcc2950ccf4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Store &amp;amp; Parse nodeId &amp;amp; browseName&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c49fa5142d2cf17&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Global Address Space Folder Browse&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;335878527020598c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 3&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b208f2e8cba6205&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;p&amp;gt;Namespace 5&amp;lt;/p&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder-arrow-down&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;52dd2e5dcddad58f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyObjects&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;p&amp;gt;Namespace 6&amp;lt;/p&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;inline-content&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1110,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a5acdccfd2033aec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticArrayVariables&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1140,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;157322c9c360446d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AnalogItemArrays&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1130,&#92;&quot;y&#92;&quot;:460,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;78a012e5db377fd9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;ca62be3e01388319&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice&#92;&quot;,&#92;&quot;order&#92;&quot;:6,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div class=&#92;&#92;&#92;&quot;d-flex align-center ml-3&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;v-icon color=&#92;&#92;&#92;&quot;black&#92;&#92;&#92;&quot; icon=&#92;&#92;&#92;&quot;mdi-folder&#92;&#92;&#92;&quot; size=&#92;&#92;&#92;&quot;large&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;/v-icon&amp;gt; &#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Endpoint&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;opc.tcp://192.168.56.1:53530/OPCUA/SimulationServer&#92;&quot;,&#92;&quot;secpol&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;secmode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;none&#92;&quot;:true,&#92;&quot;login&#92;&quot;:false,&#92;&quot;usercert&#92;&quot;:false,&#92;&quot;usercertificate&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;userprivatekey&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef9998baf5f61e8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot; Address Space Folder Structure&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;OPC UA&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/opcua&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;My Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;ui-control&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;navigationStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;61eee6fc60281b9b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default Theme&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;},&#92;&quot;sizes&#92;&quot;:{&#92;&quot;pagePadding&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupGap&#92;&quot;:&#92;&quot;12px&#92;&quot;,&#92;&quot;groupBorderRadius&#92;&quot;:&#92;&quot;4px&#92;&quot;,&#92;&quot;widgetGap&#92;&quot;:&#92;&quot;12px&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Simulation Values &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;9659d40ac9063764&#92;&quot;,&#92;&quot;9f5b597ec8179fb4&#92;&quot;,&#92;&quot;a8d919f497fcff04&#92;&quot;,&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;ec5dca5eb9d4971b&#92;&quot;,&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;4d9b758e39555124&#92;&quot;,&#92;&quot;da468bc150517fa6&#92;&quot;,&#92;&quot;82aa12173dd7bbca&#92;&quot;,&#92;&quot;57d8777e34b55b7b&#92;&quot;,&#92;&quot;10877909d1daf6fe&#92;&quot;,&#92;&quot;c4d4a3b0df372e4c&#92;&quot;,&#92;&quot;b0cf511f824f2a86&#92;&quot;,&#92;&quot;f2efc6b419414c9a&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:599,&#92;&quot;w&#92;&quot;:1372,&#92;&quot;h&#92;&quot;:302},{&#92;&quot;id&#92;&quot;:&#92;&quot;9659d40ac9063764&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:570,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ec5dca5eb9d4971b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9f5b597ec8179fb4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update Simulation Values @ 1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.Simulation.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:300,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9659d40ac9063764&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a8d919f497fcff04&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Simulation Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Counter Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[1].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:680,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;10877909d1daf6fe&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec5dca5eb9d4971b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:760,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;13f5c98b7fd5f5da&#92;&quot;,&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;4d9b758e39555124&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1780cb86597d3c67&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Random Number Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[2].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c4d4a3b0df372e4c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1a2fcac87247cda4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Sawtooth Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[3].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b0cf511f824f2a86&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d9b758e39555124&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get Sawtooth Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1080,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f2efc6b419414c9a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;da468bc150517fa6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Discard Empty Datasets&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:780,&#92;&quot;y&#92;&quot;:720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;82aa12173dd7bbca&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse Simulation Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;57d8777e34b55b7b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;10877909d1daf6fe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Counter&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:3,&#92;&quot;height&#92;&quot;:3,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#5cd65c&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;15&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ffc800&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ea5353&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;30&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:680,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4d4a3b0df372e4c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1350,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b0cf511f824f2a86&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:800,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f2efc6b419414c9a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8557072f05e4bda0&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Sinusoid&#92;&quot;,&#92;&quot;order&#92;&quot;:9007199254740991,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;category&#92;&quot;:&#92;&quot;Sawtooth&#92;&quot;,&#92;&quot;categoryType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;xAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;xAxisPropertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;xAxisType&#92;&quot;:&#92;&quot;time&#92;&quot;,&#92;&quot;yAxisProperty&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;append&#92;&quot;,&#92;&quot;pointShape&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;pointRadius&#92;&quot;:4,&#92;&quot;showLegend&#92;&quot;:true,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:860,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af263064820fb7d0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Simulation values&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read StaticData Values &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e998aa804042128b&#92;&quot;,&#92;&quot;6c9b7d4d195a1e9a&#92;&quot;,&#92;&quot;cd097b744d0ec625&#92;&quot;,&#92;&quot;18d21607c87ab153&#92;&quot;,&#92;&quot;7b5143c4960f92a1&#92;&quot;,&#92;&quot;0625b0cf6f546a4a&#92;&quot;,&#92;&quot;9d899fbb4d1648b3&#92;&quot;,&#92;&quot;6e1edc31687dde54&#92;&quot;,&#92;&quot;051e1f282076fed2&#92;&quot;,&#92;&quot;de2a1c3e380f743b&#92;&quot;,&#92;&quot;c74606c48ccf5a40&#92;&quot;,&#92;&quot;053bda13f2a2eabe&#92;&quot;,&#92;&quot;277dcf430dc86996&#92;&quot;,&#92;&quot;d708e6264cec0070&#92;&quot;],&#92;&quot;x&#92;&quot;:84,&#92;&quot;y&#92;&quot;:939,&#92;&quot;w&#92;&quot;:1382,&#92;&quot;h&#92;&quot;:202},{&#92;&quot;id&#92;&quot;:&#92;&quot;e998aa804042128b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b5143c4960f92a1&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6c9b7d4d195a1e9a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update AnalogItemArrays Values @ 1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.AnalogItemArrays.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e998aa804042128b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cd097b744d0ec625&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read StaticData Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;18d21607c87ab153&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get ByteAnalogItemArray Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;$string(payload[0].item.value)&#92;&#92;t&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;277dcf430dc86996&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b5143c4960f92a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;18d21607c87ab153&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0625b0cf6f546a4a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;051e1f282076fed2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9d899fbb4d1648b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update StaticArrayVariables Values @1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.StaticData.StaticArrayVariables.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0625b0cf6f546a4a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6e1edc31687dde54&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get BooleanArray Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1050,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d708e6264cec0070&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;051e1f282076fed2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:830,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6e1edc31687dde54&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de2a1c3e380f743b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Discard Empty Datasets&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:820,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c74606c48ccf5a40&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse StaticData Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1070,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;053bda13f2a2eabe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:980,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;277dcf430dc86996&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;ByteAnalogItemArray&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1340,&#92;&quot;y&#92;&quot;:1020,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d708e6264cec0070&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;5afdbddf71507886&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;BooleanArray&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1320,&#92;&quot;y&#92;&quot;:1100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3d4f386e812e8b5f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;StaticData Values&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read MyDevice Values &amp;amp; Display on Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;bfe4274963a84e2e&#92;&quot;,&#92;&quot;0662c62c7f0cfac0&#92;&quot;,&#92;&quot;249c223139c5779e&#92;&quot;,&#92;&quot;efb293f13af17dc1&#92;&quot;,&#92;&quot;507d2c11c7586957&#92;&quot;,&#92;&quot;3b7695a52a1bf6e0&#92;&quot;,&#92;&quot;594ec38acadc9673&#92;&quot;,&#92;&quot;d4e2915ba92db8a6&#92;&quot;,&#92;&quot;85619f0eab615ac7&#92;&quot;,&#92;&quot;cd4941a8db3edcb6&#92;&quot;,&#92;&quot;ad91d2ca81697fc2&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:1179,&#92;&quot;w&#92;&quot;:1292,&#92;&quot;h&#92;&quot;:182},{&#92;&quot;id&#92;&quot;:&#92;&quot;bfe4274963a84e2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Browser&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;items&#92;&quot;:[],&#92;&quot;name&#92;&quot;:&#92;&quot;OPC Client Namespace Browse&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:1280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;507d2c11c7586957&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0662c62c7f0cfac0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read MyDevice Values @ 1 second&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;Objects.MyObjects.MyDevice.nodeId&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:290,&#92;&quot;y&#92;&quot;:1280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bfe4274963a84e2e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;249c223139c5779e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read MyDevice&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:1240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;efb293f13af17dc1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyLevel Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[0].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1030,&#92;&quot;y&#92;&quot;:1260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cd4941a8db3edcb6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;507d2c11c7586957&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;empty check&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;nempty&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:810,&#92;&quot;y&#92;&quot;:1280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;efb293f13af17dc1&#92;&quot;,&#92;&quot;3b7695a52a1bf6e0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3b7695a52a1bf6e0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MySwitch Value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload[4].item.value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1040,&#92;&quot;y&#92;&quot;:1320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad91d2ca81697fc2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;594ec38acadc9673&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1260,&#92;&quot;y&#92;&quot;:1220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d4e2915ba92db8a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse MyDevice Values&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1040,&#92;&quot;y&#92;&quot;:1220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;85619f0eab615ac7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Discard Empty Datasets&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:800,&#92;&quot;y&#92;&quot;:1240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cd4941a8db3edcb6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Level&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:3,&#92;&quot;height&#92;&quot;:3,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gauge-half&#92;&quot;,&#92;&quot;gstyle&#92;&quot;:&#92;&quot;needle&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;Level&#92;&quot;,&#92;&quot;units&#92;&quot;:&#92;&quot;%&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;prefix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;suffix&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;segments&#92;&quot;:[{&#92;&quot;from&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;25&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;50&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;},{&#92;&quot;from&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;}],&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;sizeThickness&#92;&quot;:16,&#92;&quot;sizeGap&#92;&quot;:4,&#92;&quot;sizeKeyThickness&#92;&quot;:8,&#92;&quot;styleRounded&#92;&quot;:true,&#92;&quot;styleGlow&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1250,&#92;&quot;y&#92;&quot;:1260,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad91d2ca81697fc2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-led&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;25f95391088d4a08&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:-1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;Switch&#92;&quot;,&#92;&quot;labelPlacement&#92;&quot;:&#92;&quot;left&#92;&quot;,&#92;&quot;labelAlignment&#92;&quot;:&#92;&quot;flex-start&#92;&quot;,&#92;&quot;states&#92;&quot;:[{&#92;&quot;value&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#ff0000&#92;&quot;},{&#92;&quot;value&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;valueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#00ff00&#92;&quot;}],&#92;&quot;allowColorForValueInMessage&#92;&quot;:false,&#92;&quot;shape&#92;&quot;:&#92;&quot;circle&#92;&quot;,&#92;&quot;showBorder&#92;&quot;:true,&#92;&quot;showGlow&#92;&quot;:true,&#92;&quot;x&#92;&quot;:1250,&#92;&quot;y&#92;&quot;:1320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyDevice Status &amp;amp; Control&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;44d3feb2a1143d7b&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;showTitle&#92;&quot;:true,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Mydevices values to OPC UA Server&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;a66583d91b581cd8&#92;&quot;,&#92;&quot;3e8cb6e199012155&#92;&quot;,&#92;&quot;9fa33d1c9c621611&#92;&quot;,&#92;&quot;fb7f57b4da5883ae&#92;&quot;,&#92;&quot;9c5ff104eb9c8b10&#92;&quot;,&#92;&quot;77bcb828bec95336&#92;&quot;,&#92;&quot;afa83dbb46449d4a&#92;&quot;,&#92;&quot;fa08f0ed04296363&#92;&quot;,&#92;&quot;9f591797b56c565d&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:1439,&#92;&quot;w&#92;&quot;:792,&#92;&quot;h&#92;&quot;:182},{&#92;&quot;id&#92;&quot;:&#92;&quot;a66583d91b581cd8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=6;s=MySwitch&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Boolean&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Toggle MySwitch&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3e8cb6e199012155&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3e8cb6e199012155&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Write MySwitch&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9fa33d1c9c621611&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard Input&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb7f57b4da5883ae&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Item&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;item&#92;&quot;:&#92;&quot;ns=6;s=MyLevel&#92;&quot;,&#92;&quot;datatype&#92;&quot;:&#92;&quot;Double&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Modify MyLevel&#92;&quot;,&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;9c5ff104eb9c8b10&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9c5ff104eb9c8b10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;write&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Write MyLevel&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;77bcb828bec95336&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Call OPC UA Item&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;afa83dbb46449d4a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write OPC UA Item to Client&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:740,&#92;&quot;y&#92;&quot;:1480,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa08f0ed04296363&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Toggle MySwitch&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;style&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;onvalue&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;onvalueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;onicon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;oncolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offvalue&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;offvalueType&#92;&quot;:&#92;&quot;bool&#92;&quot;,&#92;&quot;officon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;offcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:1520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a66583d91b581cd8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9f591797b56c565d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-slider&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;3de6c861611c3afa&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Modify MyLevel&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;outs&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;thumbLabel&#92;&quot;:true,&#92;&quot;min&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;step&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:1580,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fb7f57b4da5883ae&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Alarms &amp;amp; Events From OPC UA Server&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;90fb4ca64a642edf&#92;&quot;,&#92;&quot;b76f64786bc681c3&#92;&quot;,&#92;&quot;71e24b671bc03fb8&#92;&quot;,&#92;&quot;c7438df35b506470&#92;&quot;,&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;04992b24a3836f19&#92;&quot;,&#92;&quot;325068cb935cd6d1&#92;&quot;,&#92;&quot;5b4d1bd8b342fc05&#92;&quot;,&#92;&quot;ba1ea89438335cb8&#92;&quot;,&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;1e3956200997581f&#92;&quot;,&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;,&#92;&quot;62b2e14ce0429eef&#92;&quot;],&#92;&quot;x&#92;&quot;:94,&#92;&quot;y&#92;&quot;:1679,&#92;&quot;w&#92;&quot;:1352,&#92;&quot;h&#92;&quot;:282},{&#92;&quot;id&#92;&quot;:&#92;&quot;90fb4ca64a642edf&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Call OPC UA Item&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:1820,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b76f64786bc681c3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;root&#92;&quot;:&#92;&quot;ns=6;s=MyLevel.Alarm&#92;&quot;,&#92;&quot;activatecustomevent&#92;&quot;:false,&#92;&quot;eventtype&#92;&quot;:&#92;&quot;i=2041&#92;&quot;,&#92;&quot;customeventtype&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;MyLevel Alarms&#92;&quot;,&#92;&quot;x&#92;&quot;:500,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c7438df35b506470&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;71e24b671bc03fb8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Trigger Alarm Event Capture&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;},{&#92;&quot;p&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b76f64786bc681c3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c7438df35b506470&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;OpcUa-Client&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;53f4394dbf12c6b7&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;events&#92;&quot;,&#92;&quot;deadbandtype&#92;&quot;:&#92;&quot;a&#92;&quot;,&#92;&quot;deadbandvalue&#92;&quot;:1,&#92;&quot;time&#92;&quot;:10,&#92;&quot;timeUnit&#92;&quot;:&#92;&quot;s&#92;&quot;,&#92;&quot;certificate&#92;&quot;:&#92;&quot;n&#92;&quot;,&#92;&quot;localfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;localkeyfile&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;securitymode&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;securitypolicy&#92;&quot;:&#92;&quot;None&#92;&quot;,&#92;&quot;useTransport&#92;&quot;:false,&#92;&quot;maxChunkCount&#92;&quot;:1,&#92;&quot;maxMessageSize&#92;&quot;:8192,&#92;&quot;receiveBufferSize&#92;&quot;:8192,&#92;&quot;sendBufferSize&#92;&quot;:8192,&#92;&quot;name&#92;&quot;:&#92;&quot;Get MyLevel Events&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;04992b24a3836f19&#92;&quot;],[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c7e8919b636cb51d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Text&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Message.text&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;1e3956200997581f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5952b86dae22b056&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Time&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Time&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1860,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;04992b24a3836f19&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Severity&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload.Severity&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1000,&#92;&quot;y&#92;&quot;:1920,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;62b2e14ce0429eef&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;325068cb935cd6d1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Parse Event Dataset&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:990,&#92;&quot;y&#92;&quot;:1760,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;5b4d1bd8b342fc05&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get OPC Events from Client&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:720,&#92;&quot;y&#92;&quot;:1820,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba1ea89438335cb8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display Events on Dashboard&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:1720,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d662d662c5ccb9c1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-notification&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;5355e0c476f9da3b&#92;&quot;,&#92;&quot;position&#92;&quot;:&#92;&quot;center center&#92;&quot;,&#92;&quot;colorDefault&#92;&quot;:true,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;displayTime&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;showCountdown&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;allowDismiss&#92;&quot;:true,&#92;&quot;dismissText&#92;&quot;:&#92;&quot;Close&#92;&quot;,&#92;&quot;raw&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Event Notification&#92;&quot;,&#92;&quot;x&#92;&quot;:1230,&#92;&quot;y&#92;&quot;:1800,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e3956200997581f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1240,&#92;&quot;y&#92;&quot;:1840,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0b8ac86e5e4f9f8d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event Timestamp&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1280,&#92;&quot;y&#92;&quot;:1880,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;62b2e14ce0429eef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;5b972161c4e0464e&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;a6e9abacd0bdf3b6&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec0ecb26fde8db3e&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Latest MyLevel Event Severity&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#717171&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1270,&#92;&quot;y&#92;&quot;:1920,&#92;&quot;wires&#92;&quot;:[]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow170.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-170&#39;) })&lt;/script&gt;</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/dashboard-0-1-release/</id>
        <title>First Pre-Alpha Release of the new Node-RED Dashboard</title>
        <summary>Introducing v0.0.1 – An Initial Glimpse at the Future of Dashboarding in Node-RED</summary>
        <updated>2023-07-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/dashboard-0-1-release/"/>
        <author><name></name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Just weeks ago, we at FlowFuse &lt;a href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/&quot;&gt;announced our plan&lt;/a&gt; to develop a successor to the Node-RED Dashboard. Today, we&#39;re excited to reveal the pre-alpha release of this highly anticipated project, bringing us one step closer to a new era of data visualization in Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;sneak-peek-into-the-new-node-red-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/dashboard-0-1-release/#sneak-peek-into-the-new-node-red-dashboard&quot;&gt;Sneak Peek into the New Node-RED Dashboard&lt;/a&gt;&lt;/h2&gt;
&lt;!-- ![](./images/placeholder.png &quot;new Node-RED Dashboard Overview&quot;)--&gt;
&lt;p&gt;The Node-RED Dashboard successor is now available for install as an npm package under the name &lt;a href=&quot;https://www.npmjs.com/package/@flowforge/node-red-dashboard&quot;&gt;@flowforge/node-red-dashboard&lt;/a&gt; in your Node-RED palette manager.&lt;/p&gt;
&lt;p&gt;This pre-alpha version includes the first set of Vue.js-based elements familiar to Node-RED Dashboard users:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;new Node-RED Dashboard Elements&quot; alt=&quot;&amp;quot;new Node-RED Dashboard Elements&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr-dashboard-screenshot.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This is but a hint of what&#39;s to come. The objective of these pre-alpha releases is to provide early access to the current status.&lt;/p&gt;
&lt;p&gt;The strength of the project comes from the community. Your insights, suggestions and contributions play a significant role in shaping the future of this dashboard. Keep them coming through our &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard&quot;&gt;Github page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;current-status-and-next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/dashboard-0-1-release/#current-status-and-next-steps&quot;&gt;Current Status and Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of now, we&#39;ve implemented the following Dashboard Widgets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI Text (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/38&quot;&gt;ui-text Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Text Input (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/39&quot;&gt;ui-text-input Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Range Slider (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/47&quot;&gt;ui-slider Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Dropdown/Select (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/45&quot;&gt;ui-dropdown Widget&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&#39;ve also introduced a new widget:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Markdown (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/62&quot;&gt;ui-markdown Widget&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not yet part of the first Pre-Alpha Release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toggle Switch (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/42&quot;&gt;ui-switch Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Color Picker (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/46&quot;&gt;ui-color-picker Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Number Input (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/41&quot;&gt;ui-numeric Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Form (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/49&quot;&gt;ui-form Widget&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Date selector (&lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/32&quot;&gt;ui-date-picker&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our immediate focus is to continue adding the missing elements from the original Node-RED Dashboard, releasing each as soon as they&#39;re fully developed. This will significantly increase the frequency of our releases in the upcoming weeks.&lt;/p&gt;
&lt;p&gt;In addition to these releases, we plan to publish regular blog posts titled &amp;quot;What&#39;s New in Node-RED Dashboard&amp;quot;. These posts will keep you informed of all the latest features, updates, and improvements.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/</id>
        <title>How to add images to Node-RED dashboards when using FlowFuse</title>
        <summary>Import your images into your Node-RED dashboards, wherever you are running your instances</summary>
        <updated>2023-07-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Using images in your Node-RED dashboards can significantly improve your users&#39; experience. The most common method to add images to dashboards is to store them within the filesystem of an Node-RED instance but sometimes that&#39;s not an option. How can you easily use images when working in a containerized environment such as Docker, or Kubernetes? We will also explore latest feature from FlowFuse that makes this step super easy.&lt;/p&gt;
&lt;p&gt;When designing a dashboard, images allow you to significantly enrich your content. Some examples include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;displaying maps to guide engineers to a problem which needs resolving.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;displaying pictures of specific hardware on a factory-floor which needs to be checked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;displaying physical tools which should be used to resolve a problem.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we begin, ensure you have the following custom nodes installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;@flowfuse/node-red-dashboard&lt;/a&gt; - A set of dashboard nodes for Node-RED. We will use this dashboard to demonstrate how to quickly display images using static assets. If you&#39;re a beginner and want to dive deeper, refer to &lt;a href=&quot;https://flowfuse.com/blog/2024/03/dashboard-getting-started/&quot;&gt;Getting started with FlowFuse Dashboarad&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-string&quot;&gt;node-red-contrib-string&lt;/a&gt; - A string manipulation node based on the lightweight stringjs library.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-node-base64&quot;&gt;node-red-node-base64&lt;/a&gt; - A Node-RED node to encode and decode data to and from base64.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;easily-add-images-to-node-red-dashboards-with-flowfuse%E2%80%99s-static-asset-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#easily-add-images-to-node-red-dashboards-with-flowfuse%E2%80%99s-static-asset-service&quot;&gt;Easily Add Images to Node-RED Dashboards with FlowFuse’s Static Asset Service&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowforge.com/docs/user/static-asset-service/&quot;&gt;FlowFuse&#39;s static assets&lt;/a&gt; service provides a simple way to manage images and other assets in Node-RED. Follow these steps to quickly add images to your Node-RED dashboard.&lt;/p&gt;
&lt;h3 id=&quot;steps-to-add-images-using-the-static-asset-service%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#steps-to-add-images-using-the-static-asset-service%3A&quot;&gt;Steps to Add Images Using the Static Asset Service:&lt;/a&gt;&lt;/h3&gt;
&lt;h5 id=&quot;1.-access-the-static-assets-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#1.-access-the-static-assets-service&quot;&gt;1. Access the Static Assets Service&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Log into your FlowFuse account, navigate to your &lt;strong&gt;Node-RED instance&lt;/strong&gt;, and click on the &lt;strong&gt;Static Assets Service&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;2.-create-a-new-folder-(optional)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#2.-create-a-new-folder-(optional)&quot;&gt;2. Create a New Folder (Optional)&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;New Folder&lt;/strong&gt; button to create a folder that will help you organize your assets. Provide a folder name and &lt;strong&gt;confirm&lt;/strong&gt; the creation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;3.-upload-your-image&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#3.-upload-your-image&quot;&gt;3. Upload Your Image&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Enter the folder (or skip this step if not using folders), click &lt;strong&gt;Upload&lt;/strong&gt;, select your image file, and &lt;strong&gt;confirm&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;4.-copy-the-image-path&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#4.-copy-the-image-path&quot;&gt;4. Copy the Image Path&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Once uploaded, click the &lt;strong&gt;copy icon&lt;/strong&gt; next to the image to get the path for use in Node-RED.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;5.-set-up-the-image-flow-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#5.-set-up-the-image-flow-in-node-red&quot;&gt;5. Set Up the Image Flow in Node-RED&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Open the Node-RED editor for the relevant instance.&lt;/li&gt;
&lt;li&gt;Drag an &lt;code&gt;inject&lt;/code&gt; node onto the canvas and set it to trigger immediately when the flow is deployed.&lt;/li&gt;
&lt;li&gt;Drag a &lt;code&gt;read file&lt;/code&gt; node, paste the copied file path in the &lt;strong&gt;Filename&lt;/strong&gt; field, and set the output to Single buffer object.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;6.-prepare-the-image-for-display&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#6.-prepare-the-image-for-display&quot;&gt;6. Prepare the Image for Display&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;code&gt;string&lt;/code&gt; node to convert the buffer to a base64 string. Set &lt;strong&gt;From&lt;/strong&gt; as &lt;code&gt;msg.filename&lt;/code&gt; and adjust the &lt;strong&gt;Method&lt;/strong&gt; to &lt;code&gt;getmost&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;code&gt;change&lt;/code&gt; node and configure it to add the elements shown in the following image:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The change node showing added elements&quot; alt=&quot;The change node showing added elements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;7.-display-the-image-in-the-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#7.-display-the-image-in-the-dashboard&quot;&gt;7. Display the Image in the Dashboard&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drag a &lt;code&gt;ui-template&lt;/code&gt; node onto the canvas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the code in &lt;code&gt;ui-template&lt;/code&gt; with an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, configuring the &lt;code&gt;src&lt;/code&gt; attribute with &lt;code&gt;msg.payload&lt;/code&gt;, as shown in the following code. Alternatively, you can use the following code directly if you want to display the image in the top-left corner of your dashboard header:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-146&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-146&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Teleport v&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mounted&quot;&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#app-bar-title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg.payload&quot;&lt;/span&gt; style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;height: 32px;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Teleport&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;template&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;mounted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mounted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-146&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;8.-connect-the-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#8.-connect-the-nodes&quot;&gt;8. Connect the Nodes&lt;/a&gt;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Finally connect the nodes in the following order:
the &lt;strong&gt;output&lt;/strong&gt; of the &lt;code&gt;inject&lt;/code&gt; node to the &lt;strong&gt;input&lt;/strong&gt; of the &lt;code&gt;read file&lt;/code&gt; node, then link to the &lt;code&gt;string node&lt;/code&gt;, followed by the &lt;code&gt;change&lt;/code&gt; node, and finally to the &lt;code&gt;ui-template&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;inject → read file → string → change → ui-template&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;nr-flow-171&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow171 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;stroke&#92;&quot;:&#92;&quot;#b2b3bd&#92;&quot;,&#92;&quot;stroke-opacity&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;fill&#92;&quot;:&#92;&quot;#f2f3fb&#92;&quot;,&#92;&quot;fill-opacity&#92;&quot;:&#92;&quot;0.5&#92;&quot;,&#92;&quot;label&#92;&quot;:true,&#92;&quot;label-position&#92;&quot;:&#92;&quot;nw&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;#32333b&#92;&quot;},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;3bf4c71150bd0524&#92;&quot;,&#92;&quot;4d3ca1b96c181645&#92;&quot;,&#92;&quot;315948cc6a2cc9e8&#92;&quot;,&#92;&quot;fcf061d4cc732e2e&#92;&quot;,&#92;&quot;6563d8715af4cb06&#92;&quot;,&#92;&quot;d40caa36040de881&#92;&quot;],&#92;&quot;x&#92;&quot;:514,&#92;&quot;y&#92;&quot;:699,&#92;&quot;w&#92;&quot;:1752,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;3bf4c71150bd0524&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;25f447d87d1ce5c9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display image&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;!-- Teleport the image to the #app-bar-title area when mounted --&amp;gt;&#92;&#92;n    &amp;lt;Teleport v-if=&#92;&#92;&#92;&quot;mounted&#92;&#92;&#92;&quot; to=&#92;&#92;&#92;&quot;#app-bar-title&#92;&#92;&#92;&quot;&amp;gt;&#92;&#92;n        &amp;lt;img :src=&#92;&#92;&#92;&quot;msg.payload&#92;&#92;&#92;&quot; style=&#92;&#92;&#92;&quot;height: 32px;&#92;&#92;&#92;&quot; /&amp;gt;&#92;&#92;n    &amp;lt;/Teleport&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&#92;n&#92;&#92;n&amp;lt;script&amp;gt;&#92;&#92;n    export default {&#92;&#92;n        data() {&#92;&#92;n            return {&#92;&#92;n                mounted: false&#92;&#92;n            }&#92;&#92;n        },&#92;&#92;n        mounted() {&#92;&#92;n            // Set mounted to true when the component is mounted&#92;&#92;n            this.mounted = true&#92;&#92;n        }&#92;&#92;n    }&#92;&#92;n&amp;lt;/script&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;widget:ui&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:2160,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d3ca1b96c181645&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;date&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;315948cc6a2cc9e8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;315948cc6a2cc9e8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;Images/ff-logo--wordmark--light.png&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;chunk&#92;&quot;:false,&#92;&quot;sendError&#92;&quot;:false,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;allProps&#92;&quot;:false,&#92;&quot;x&#92;&quot;:880,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d40caa36040de881&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fcf061d4cc732e2e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add the file type to the mimetype, add to image content&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;mimetype&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&quot;data:image/&#92;&#92;&#92;&quot;&amp;amp;msg.filetype&amp;amp;&#92;&#92;&#92;&quot;;base64,&#92;&#92;&#92;&quot;&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;output&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;msg.mimetype&amp;amp;msg.payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;move&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;output&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1820,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3bf4c71150bd0524&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6563d8715af4cb06&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;string&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get file type from file name&#92;&quot;,&#92;&quot;methods&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;getRightMost&#92;&quot;,&#92;&quot;params&#92;&quot;:[{&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;.&#92;&quot;}]}],&#92;&quot;prop&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;propout&#92;&quot;:&#92;&quot;filetype&#92;&quot;,&#92;&quot;object&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;objectout&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:1480,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fcf061d4cc732e2e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d40caa36040de881&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;base64&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;e50f7c57189d62f8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Convert Buffer to Base 64 String&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:1210,&#92;&quot;y&#92;&quot;:740,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6563d8715af4cb06&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;25f447d87d1ce5c9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-notification&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:false,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow171.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-171&#39;) })&lt;/script&gt;
&lt;p&gt;Using the FlowFuse Static Assets service is highly beneficial when you want to display images in Node-RED dashboards, as it saves time compared to alternative solutions. However, it’s important to note that moving Node-RED instances through a DevOps pipeline currently does not support handling static assets. This feature is expected in future updates. If you want to manage images effectively within your Node-RED dashboards, consider the alternative solutions discussed in this blog, ensuring that the movement of instances does not affect the usage of these assets.&lt;/p&gt;
&lt;h2 id=&quot;why-not-just-store-them-in-node-red&#39;s-host-operating-system%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#why-not-just-store-them-in-node-red&#39;s-host-operating-system%3F&quot;&gt;Why not just store them in Node-RED&#39;s host operating system?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Storing images locally can work well when you can access and edit the images on an operating system, but that approach doesn&#39;t scale if you are moving instances through a DevOps pipeline. It can also not work well when deploying to environments where you don&#39;t have easy access to the host operating system.&lt;/p&gt;
&lt;p&gt;How can we include images in dashboards, and be confident that a given build of an application will show the correct images, no matter where your Node-RED instances are hosted?&lt;/p&gt;
&lt;h2 id=&quot;inspiration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#inspiration&quot;&gt;Inspiration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are various solutions to this problem, I wanted to share one I came across when working with a FlowFuse customer recently. I&#39;ve modified the flows to make them more general in design, but the underlying principal is the same. I asked if I was OK to credit the customer but they said there was no need. Thanks for the inspiration, kind customer!&lt;/p&gt;
&lt;h2 id=&quot;solution-explanation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#solution-explanation&quot;&gt;Solution explanation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are three key sections to this solution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Pull the images we need from URLs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Store those images in the temporary filesystem of Node-RED&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Serve up those images as needed in the dashboard&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is possible for us to skip step 2, but I wanted to have the images stored locally, in the Node-RED instance. storing the images locally will improve the loading times of the dashboard. This is especially beneficial when your dashboard is dynamically displaying relevant images, e.g. to show an image of a specific machine which needs to be attended to.&lt;/p&gt;
&lt;p&gt;The key benefit of pulling the images from URLs this way is, no matter where you are running Node-RED, the correct images will be shown in your dashboard.&lt;/p&gt;
&lt;h2 id=&quot;prequsite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#prequsite&quot;&gt;Prequsite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before moving forward, ensure you have the following nodes installed, as the flows shared later will require them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-calc&quot;&gt;node-red-contrib-calc&lt;/a&gt; - A Node-RED node to perform basic mathematical calculations.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-image-output&quot;&gt;node-red-contrib-image-output&lt;/a&gt; - A simple way to preview and examine images in your flows.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-os&quot;&gt;node-red-contrib-os&lt;/a&gt; - Nodes for obtaining system information like CPU usage.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-string&quot;&gt;node-red-contrib-string&lt;/a&gt; - A string manipulation node based on the lightweight stringjs library.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/@flowfuse/node-red-dashboard&quot;&gt;@flowfuse/node-red-dashboard&lt;/a&gt; - A set of dashboard nodes for Node-RED.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-node-base64&quot;&gt;node-red-node-base64&lt;/a&gt; - A Node-RED node to encode and decode data to and from base64.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;file-and-file-in-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#file-and-file-in-nodes&quot;&gt;File and file-in nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ve included the flows as json below so you can try them out yourself. Please note, I&#39;m using FlowFuse&#39;s own &lt;a href=&quot;https://flowfuse.com/docs/user/filenodes/&quot;&gt;file and file-in nodes&lt;/a&gt; in these examples. If you want to use these flows on hosting other than FlowFuse, you will need to replace the nodes with the standard Node-RED file and file-in nodes.&lt;/p&gt;
&lt;h2 id=&quot;the-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#the-flows&quot;&gt;The flows&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first flow takes image URLs in an array, each image is downloaded, processed, then saved to the local file storage. Let&#39;s take a look at the flow:&lt;/p&gt;
&lt;div id=&quot;nr-flow-172&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow172 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6b8059f703d0f574&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write the images to disk from the URLs&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;04fb6911559797a0&#92;&quot;,&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;6fcca5cfee2bcb89&#92;&quot;],&#92;&quot;x&#92;&quot;:38,&#92;&quot;y&#92;&quot;:53,&#92;&quot;w&#92;&quot;:1004,&#92;&quot;h&#92;&quot;:434},{&#92;&quot;id&#92;&quot;:&#92;&quot;04fb6911559797a0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6b8059f703d0f574&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject the image URLs to download&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;e635ceb0577a86d5&#92;&quot;,&#92;&quot;29fe40a054be5b2b&#92;&quot;,&#92;&quot;1e81a35c27aae6ad&#92;&quot;],&#92;&quot;x&#92;&quot;:74,&#92;&quot;y&#92;&quot;:79,&#92;&quot;w&#92;&quot;:502,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;e635ceb0577a86d5&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;04fb6911559797a0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send in image URLs as an array&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[&#92;&#92;&#92;&quot;https://openjsf.org/wp-content/uploads/sites/84/2023/02/ff-logo-wordmark-light_4x.png&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;https://nodered.org/images/nr-image-1.png&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;/img/screen-pseudo-overview-2QvTVle3Mr-384.avif&#92;&#92;&#92;&quot;]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:250,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;29fe40a054be5b2b&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;29fe40a054be5b2b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;04fb6911559797a0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;1e81a35c27aae6ad&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e81a35c27aae6ad&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;04fb6911559797a0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 3&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;f582702ec222069c&#92;&quot;],&#92;&quot;x&#92;&quot;:535,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6b8059f703d0f574&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Download the images&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;453f3b9d7d312bd2&#92;&quot;,&#92;&quot;ecbd7b1a410ecd9d&#92;&quot;,&#92;&quot;4d650baa2118036e&#92;&quot;,&#92;&quot;f582702ec222069c&#92;&quot;],&#92;&quot;x&#92;&quot;:84,&#92;&quot;y&#92;&quot;:179,&#92;&quot;w&#92;&quot;:532,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;453f3b9d7d312bd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http request&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get the image&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;GET&#92;&quot;,&#92;&quot;ret&#92;&quot;:&#92;&quot;bin&#92;&quot;,&#92;&quot;paytoqs&#92;&quot;:&#92;&quot;ignore&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tls&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;persist&#92;&quot;:false,&#92;&quot;proxy&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;insecureHTTPParser&#92;&quot;:false,&#92;&quot;authType&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;senderr&#92;&quot;:false,&#92;&quot;headers&#92;&quot;:[],&#92;&quot;x&#92;&quot;:460,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;4d650baa2118036e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ecbd7b1a410ecd9d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set URL to download&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;move&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;url&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:260,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;453f3b9d7d312bd2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4d650baa2118036e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 1&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;8bc38803dec97185&#92;&quot;],&#92;&quot;x&#92;&quot;:575,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f582702ec222069c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;8a3c077f0f85a905&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 3&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;1e81a35c27aae6ad&#92;&quot;],&#92;&quot;x&#92;&quot;:125,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ecbd7b1a410ecd9d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6b8059f703d0f574&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Save the images to the local storage&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;95c819560d22f394&#92;&quot;,&#92;&quot;0fe7f013b6356c5d&#92;&quot;,&#92;&quot;7edc6cb2b0d243db&#92;&quot;,&#92;&quot;829bfc8e6e293ada&#92;&quot;,&#92;&quot;8bc38803dec97185&#92;&quot;,&#92;&quot;98980d88013c6e12&#92;&quot;],&#92;&quot;x&#92;&quot;:84,&#92;&quot;y&#92;&quot;:279,&#92;&quot;w&#92;&quot;:932,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;95c819560d22f394&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;base64&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;convert to base64&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:250,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;829bfc8e6e293ada&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0fe7f013b6356c5d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write file to storage&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:850,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;98980d88013c6e12&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7edc6cb2b0d243db&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;string&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get filename from the URL&#92;&quot;,&#92;&quot;methods&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;getRightMost&#92;&quot;,&#92;&quot;params&#92;&quot;:[{&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;/&#92;&quot;}]}],&#92;&quot;prop&#92;&quot;:&#92;&quot;responseUrl&#92;&quot;,&#92;&quot;propout&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;object&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;objectout&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0fe7f013b6356c5d&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;829bfc8e6e293ada&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;image&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;preview&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;150&#92;&quot;,&#92;&quot;data&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;dataType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;thumbnail&#92;&quot;:false,&#92;&quot;active&#92;&quot;:true,&#92;&quot;pass&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7edc6cb2b0d243db&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8bc38803dec97185&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 1&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;4d650baa2118036e&#92;&quot;],&#92;&quot;x&#92;&quot;:125,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;95c819560d22f394&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;98980d88013c6e12&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;22c5026dd58e418b&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 2&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;1e94b5bab542830a&#92;&quot;],&#92;&quot;x&#92;&quot;:975,&#92;&quot;y&#92;&quot;:320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6fcca5cfee2bcb89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6b8059f703d0f574&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Output a debug once all images have been processed&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;d1a6feea3ac829c6&#92;&quot;,&#92;&quot;119f8008752bc4fb&#92;&quot;,&#92;&quot;1e94b5bab542830a&#92;&quot;],&#92;&quot;x&#92;&quot;:64,&#92;&quot;y&#92;&quot;:379,&#92;&quot;w&#92;&quot;:382,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;d1a6feea3ac829c6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6fcca5cfee2bcb89&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 140&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;full&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;119f8008752bc4fb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6fcca5cfee2bcb89&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d1a6feea3ac829c6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e94b5bab542830a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;c6f2a894be05d857&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;6fcca5cfee2bcb89&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 2&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;98980d88013c6e12&#92;&quot;],&#92;&quot;x&#92;&quot;:105,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;119f8008752bc4fb&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow172.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-172&#39;) })&lt;/script&gt;
&lt;p&gt;We&#39;ve now downloaded the images we need, and saved them to our local storage, to make them load more quickly when a user views them in the dashboard.&lt;/p&gt;
&lt;p&gt;Onto the second flow, which will get the images from the local storage and then load them into the dashboard. Let&#39;s take a look at it:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Get the images from the local storage and place them in a dashboard&quot; alt=&quot;Get the images from the local storage and place them in a dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/load-images-from-disk-and-show-in-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can import this flow into Node-RED using the code below:&lt;/p&gt;
&lt;div id=&quot;nr-flow-173&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow173 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get the images from the filestore and display in the Dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;1e54acecec6bd411&#92;&quot;,&#92;&quot;99aaee673fc70bc2&#92;&quot;],&#92;&quot;x&#92;&quot;:1228,&#92;&quot;y&#92;&quot;:3733,&#92;&quot;w&#92;&quot;:974,&#92;&quot;h&#92;&quot;:654},{&#92;&quot;id&#92;&quot;:&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get the images from the local storage&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;c698b2945583e126&#92;&quot;,&#92;&quot;ab22b978a2f5d80f&#92;&quot;,&#92;&quot;2836914f9b643e34&#92;&quot;,&#92;&quot;8e32aba67d9ac9d4&#92;&quot;],&#92;&quot;x&#92;&quot;:1264,&#92;&quot;y&#92;&quot;:3899,&#92;&quot;w&#92;&quot;:492,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;c698b2945583e126&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;image&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;preview&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;150&#92;&quot;,&#92;&quot;data&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;dataType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;thumbnail&#92;&quot;:false,&#92;&quot;active&#92;&quot;:true,&#92;&quot;pass&#92;&quot;:true,&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;x&#92;&quot;:1620,&#92;&quot;y&#92;&quot;:3940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8e32aba67d9ac9d4&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ab22b978a2f5d80f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read file from storage&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;utf8&#92;&quot;,&#92;&quot;chunk&#92;&quot;:false,&#92;&quot;sendError&#92;&quot;:false,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;allProps&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1440,&#92;&quot;y&#92;&quot;:3940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c698b2945583e126&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2836914f9b643e34&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 4&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;a9958e1e4b07191a&#92;&quot;],&#92;&quot;x&#92;&quot;:1305,&#92;&quot;y&#92;&quot;:3940,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ab22b978a2f5d80f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8e32aba67d9ac9d4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;be421f8265c4c090&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 5&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;bbdd3a2e737e1074&#92;&quot;],&#92;&quot;x&#92;&quot;:1715,&#92;&quot;y&#92;&quot;:3940,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Prepare each image to be shown in the dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;54f0e7fddf447d10&#92;&quot;,&#92;&quot;d856077cc6d37093&#92;&quot;,&#92;&quot;bbdd3a2e737e1074&#92;&quot;,&#92;&quot;2d29c953bcdab787&#92;&quot;],&#92;&quot;x&#92;&quot;:1264,&#92;&quot;y&#92;&quot;:3999,&#92;&quot;w&#92;&quot;:832,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;54f0e7fddf447d10&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Add the file type to the mimetype, add to image content&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;mimetype&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&quot;data:image/&#92;&#92;&#92;&quot;&amp;amp;msg.filetype&amp;amp;&#92;&#92;&#92;&quot;;base64,&#92;&#92;&#92;&quot;&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;output&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;msg.mimetype&amp;amp;msg.payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;move&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;output&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1810,&#92;&quot;y&#92;&quot;:4040,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;2d29c953bcdab787&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d856077cc6d37093&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;string&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get file type from file name&#92;&quot;,&#92;&quot;methods&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;getRightMost&#92;&quot;,&#92;&quot;params&#92;&quot;:[{&#92;&quot;type&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;value&#92;&quot;:&#92;&quot;.&#92;&quot;}]}],&#92;&quot;prop&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;propout&#92;&quot;:&#92;&quot;filetype&#92;&quot;,&#92;&quot;object&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;objectout&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:1460,&#92;&quot;y&#92;&quot;:4040,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;54f0e7fddf447d10&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bbdd3a2e737e1074&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 5&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;8e32aba67d9ac9d4&#92;&quot;],&#92;&quot;x&#92;&quot;:1305,&#92;&quot;y&#92;&quot;:4040,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d856077cc6d37093&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2d29c953bcdab787&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;d2dc98b4f3d6b968&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 6&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;c5e4febe48363987&#92;&quot;],&#92;&quot;x&#92;&quot;:2055,&#92;&quot;y&#92;&quot;:4040,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send the images to the correct section of the dashboard&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;fa873d7bccd2b6be&#92;&quot;,&#92;&quot;c5e4febe48363987&#92;&quot;,&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;,&#92;&quot;fb0c76a6934b0a7f&#92;&quot;,&#92;&quot;4e4105a9774c7b5c&#92;&quot;,&#92;&quot;917c842a1b46ad4c&#92;&quot;],&#92;&quot;x&#92;&quot;:1264,&#92;&quot;y&#92;&quot;:4099,&#92;&quot;w&#92;&quot;:912,&#92;&quot;h&#92;&quot;:162},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa873d7bccd2b6be&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;switch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Send the image to the correct section of the dashboard&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;filename&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;ff-logo-wordmark-light_4x.png&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;screen-pseudo-overview-2QvTVle3Mr-384.avif&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;},{&#92;&quot;t&#92;&quot;:&#92;&quot;eq&#92;&quot;,&#92;&quot;v&#92;&quot;:&#92;&quot;nr-image-1.png&#92;&quot;,&#92;&quot;vt&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;checkall&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;repair&#92;&quot;:false,&#92;&quot;outputs&#92;&quot;:3,&#92;&quot;x&#92;&quot;:1550,&#92;&quot;y&#92;&quot;:4180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;917c842a1b46ad4c&#92;&quot;],[&#92;&quot;4e4105a9774c7b5c&#92;&quot;],[&#92;&quot;fb0c76a6934b0a7f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c5e4febe48363987&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 6&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;2d29c953bcdab787&#92;&quot;],&#92;&quot;x&#92;&quot;:1305,&#92;&quot;y&#92;&quot;:4180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fa873d7bccd2b6be&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 7&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;c9de7384c9ca672f&#92;&quot;],&#92;&quot;x&#92;&quot;:2135,&#92;&quot;y&#92;&quot;:4180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fb0c76a6934b0a7f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec62d482d77f7908&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display the image on the Dashboard&#92;&quot;,&#92;&quot;order&#92;&quot;:6,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div&amp;gt;&#92;&#92;n        &amp;lt;img :src= &#92;&#92;&#92;&quot;msg.paylaod&#92;&#92;&#92;&quot; alt=&#92;&#92;&#92;&quot;Image loaded from the filestore&#92;&#92;&#92;&quot; style=&#92;&#92;&#92;&quot;width:100%&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;br&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1930,&#92;&quot;y&#92;&quot;:4220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4e4105a9774c7b5c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec62d482d77f7908&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display the image on the Dashboard&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;width&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div&amp;gt;&#92;&#92;n        &amp;lt;img :src= &#92;&#92;&#92;&quot;msg.paylaod&#92;&#92;&#92;&quot; alt=&#92;&#92;&#92;&quot;Image loaded from the filestore&#92;&#92;&#92;&quot; style=&#92;&#92;&#92;&quot;width:100%&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;br&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1930,&#92;&quot;y&#92;&quot;:4180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;917c842a1b46ad4c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-template&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;b9029adc6097bd14&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ec62d482d77f7908&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Display the image on the Dashboard&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;head&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&amp;lt;template&amp;gt;&#92;&#92;n    &amp;lt;div&amp;gt;&#92;&#92;n        &amp;lt;img :src= &#92;&#92;&#92;&quot;msg.paylaod&#92;&#92;&#92;&quot; alt=&#92;&#92;&#92;&quot;Image loaded from the filestore&#92;&#92;&#92;&quot; style=&#92;&#92;&#92;&quot;width:100%&#92;&#92;&#92;&quot;&amp;gt;&amp;lt;br&amp;gt;&#92;&#92;n    &amp;lt;/div&amp;gt;&#92;&#92;n&amp;lt;/template&amp;gt;&#92;&quot;,&#92;&quot;storeOutMessages&#92;&quot;:true,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;resendOnRefresh&#92;&quot;:true,&#92;&quot;templateScope&#92;&quot;:&#92;&quot;local&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1930,&#92;&quot;y&#92;&quot;:4140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ec62d482d77f7908&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;page&#92;&quot;:&#92;&quot;550c9ac3b2ed01c9&#92;&quot;,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;showTitle&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;disabled&#92;&quot;:&#92;&quot;false&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;550c9ac3b2ed01c9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-page&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;25f447d87d1ce5c9&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;home&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;grid&#92;&quot;,&#92;&quot;theme&#92;&quot;:&#92;&quot;c68088445147719b&#92;&quot;,&#92;&quot;breakpoints&#92;&quot;:[{&#92;&quot;name&#92;&quot;:&#92;&quot;Default&#92;&quot;,&#92;&quot;px&#92;&quot;:0,&#92;&quot;cols&#92;&quot;:3},{&#92;&quot;name&#92;&quot;:&#92;&quot;Tablet&#92;&quot;,&#92;&quot;px&#92;&quot;:576,&#92;&quot;cols&#92;&quot;:6},{&#92;&quot;name&#92;&quot;:&#92;&quot;Small Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:768,&#92;&quot;cols&#92;&quot;:9},{&#92;&quot;name&#92;&quot;:&#92;&quot;Desktop&#92;&quot;,&#92;&quot;px&#92;&quot;:1024,&#92;&quot;cols&#92;&quot;:12}],&#92;&quot;order&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;visible&#92;&quot;:true,&#92;&quot;disabled&#92;&quot;:false},{&#92;&quot;id&#92;&quot;:&#92;&quot;25f447d87d1ce5c9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-base&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Dashboard&#92;&quot;,&#92;&quot;path&#92;&quot;:&#92;&quot;/dashboard&#92;&quot;,&#92;&quot;includeClientData&#92;&quot;:true,&#92;&quot;acceptsClientConfig&#92;&quot;:[&#92;&quot;ui-control&#92;&quot;,&#92;&quot;ui-notification&#92;&quot;],&#92;&quot;showPathInSidebar&#92;&quot;:false,&#92;&quot;showPageTitle&#92;&quot;:false,&#92;&quot;titleBarStyle&#92;&quot;:&#92;&quot;default&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;c68088445147719b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-theme&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Theme Name&#92;&quot;,&#92;&quot;colors&#92;&quot;:{&#92;&quot;surface&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;primary&#92;&quot;:&#92;&quot;#0094ce&#92;&quot;,&#92;&quot;bgPage&#92;&quot;:&#92;&quot;#eeeeee&#92;&quot;,&#92;&quot;groupBg&#92;&quot;:&#92;&quot;#ffffff&#92;&quot;,&#92;&quot;groupOutline&#92;&quot;:&#92;&quot;#cccccc&#92;&quot;}},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e54acecec6bd411&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Output a debug once all images have been processed&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;c9de7384c9ca672f&#92;&quot;,&#92;&quot;b073cd4970e6ddf2&#92;&quot;,&#92;&quot;c1b52f44fd4260b3&#92;&quot;],&#92;&quot;x&#92;&quot;:1254,&#92;&quot;y&#92;&quot;:4279,&#92;&quot;w&#92;&quot;:392,&#92;&quot;h&#92;&quot;:82},{&#92;&quot;id&#92;&quot;:&#92;&quot;c9de7384c9ca672f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e54acecec6bd411&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link in 7&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;d80e5a54a7c5b2f8&#92;&quot;],&#92;&quot;x&#92;&quot;:1295,&#92;&quot;y&#92;&quot;:4320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b073cd4970e6ddf2&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b073cd4970e6ddf2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;join&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e54acecec6bd411&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;build&#92;&quot;:&#92;&quot;object&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;propertyType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;key&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;joiner&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;joinerType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;accumulate&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;count&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reduceRight&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1380,&#92;&quot;y&#92;&quot;:4320,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c1b52f44fd4260b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c1b52f44fd4260b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;1e54acecec6bd411&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 141&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1530,&#92;&quot;y&#92;&quot;:4320,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;group&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;596006fe79275d55&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject the image files&#39; names&#92;&quot;,&#92;&quot;style&#92;&quot;:{&#92;&quot;label&#92;&quot;:true},&#92;&quot;nodes&#92;&quot;:[&#92;&quot;11787d1ab6c8a9ec&#92;&quot;,&#92;&quot;49b8f3cce48dd5a9&#92;&quot;,&#92;&quot;a9958e1e4b07191a&#92;&quot;,&#92;&quot;c452f250e1303c69&#92;&quot;,&#92;&quot;08b30802899573a6&#92;&quot;],&#92;&quot;x&#92;&quot;:1254,&#92;&quot;y&#92;&quot;:3759,&#92;&quot;w&#92;&quot;:782,&#92;&quot;h&#92;&quot;:122},{&#92;&quot;id&#92;&quot;:&#92;&quot;11787d1ab6c8a9ec&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:1350,&#92;&quot;y&#92;&quot;:3800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c452f250e1303c69&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49b8f3cce48dd5a9&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;split&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;splt&#92;&quot;:&#92;&quot;&#92;&#92;&#92;&#92;n&#92;&quot;,&#92;&quot;spltType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;arraySplt&#92;&quot;:1,&#92;&quot;arraySpltType&#92;&quot;:&#92;&quot;len&#92;&quot;,&#92;&quot;stream&#92;&quot;:false,&#92;&quot;addname&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:1910,&#92;&quot;y&#92;&quot;:3800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a9958e1e4b07191a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a9958e1e4b07191a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;link out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;link out 4&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;link&#92;&quot;,&#92;&quot;links&#92;&quot;:[&#92;&quot;2836914f9b643e34&#92;&quot;],&#92;&quot;x&#92;&quot;:1995,&#92;&quot;y&#92;&quot;:3800,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c452f250e1303c69&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Image file names as an array&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;[&#92;&#92;&#92;&quot;ff-logo-wordmark-light_4x.png&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;screen-pseudo-overview-2QvTVle3Mr-384.avif&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;nr-image-1.png&#92;&#92;&#92;&quot;]&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;json&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:1720,&#92;&quot;y&#92;&quot;:3800,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49b8f3cce48dd5a9&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;08b30802899573a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui-event&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;d4aa6dd5b63a56de&#92;&quot;,&#92;&quot;g&#92;&quot;:&#92;&quot;99aaee673fc70bc2&#92;&quot;,&#92;&quot;ui&#92;&quot;:&#92;&quot;25f447d87d1ce5c9&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Update images on dashboard open&#92;&quot;,&#92;&quot;x&#92;&quot;:1420,&#92;&quot;y&#92;&quot;:3840,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;c452f250e1303c69&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow173.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-173&#39;) })&lt;/script&gt;
&lt;p&gt;I have also included some simple dashboard elements you can view alongside the images. Let&#39;s take a look at the dashboard:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The dashboard showing our images alongside other standard elements&quot; alt=&quot;The dashboard showing our images alongside other standard elements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/the-dashboard.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you import these flows into Node-RED, you should see the images automatically loaded into the dashboard when you view it. You can also replace the URLs and file paths to try using some different images if you&#39;d like to.&lt;/p&gt;
&lt;h2 id=&quot;more-things-to-try&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#more-things-to-try&quot;&gt;More things to try&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this example, the images are static but it&#39;s simple to load images depending on the state of the flow. As mentioned in this article&#39;s introduction, you could display context aware images guiding the user of the dashboard to a specific location on a map, to complete a maintenance task. If you&#39;re interested in seeing examples of dynamic image loading please comment below.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/images-in-node-red-dashboards/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Images can significantly enhance dashboards, but ensuring their proper display in different Node-RED hosting environments, especially within DevOps pipelines, can be challenging. The techniques discussed here enable effective use of images in dashboards, even within containerized setups. Additionally, if you are using FlowFuse, the new features simplify adding and managing static assets.
I&#39;d love to hear your comments and suggestions on this article. please tell us what you think about this article, and how you might use these techniques in the comments section below.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/</id>
        <title>FlowFuse 1.9.3 and Device Agent 1.9.5 released</title>
        <summary>A maintenance release to improve the Device Agent editor experience</summary>
        <updated>2023-07-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;FlowFuse and the Device Agent both received updates yesterday that bring improvements to the Device Agent editor experience, making it more resilient to network issues.&lt;/p&gt;
&lt;h2 id=&quot;improving-the-device-agent-editor-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#improving-the-device-agent-editor-experience&quot;&gt;Improving the Device Agent editor experience&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The ability to remotely edit flows running the Device Agent has been warmly welcomed by many users on the platform. Along with that comes great feedback we can use to continue improving the user experience.&lt;/p&gt;
&lt;p&gt;Some early feedback identified issues with the resilience of the tunnel we connect between the Device Agent and the platform. If the tunnel was interrupted for any reason, the user would have to manually set it up again.&lt;/p&gt;
&lt;p&gt;With the FlowFuse 1.9.3 release, now running FlowFuse Cloud, along with the latest version of the Device Agent, we have made the tunnel much more resilient. It can now restablish itself without any intervention from the user - making for a much more seamless experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2488&quot;&gt;#2488&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2507&quot;&gt;#2507&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-new-features-and-bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#other-new-features-and-bug-fixes&quot;&gt;Other New Features and Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fixes incorrect &#39;start-failed&#39; notifications when restarting an instance &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2505&quot;&gt;#2505&lt;/a&gt; The system log now includes more information about the callingThe FlowFuse device agent is now supported on Windows &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/78&quot;&gt;#78&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ensures the system logging captures the proper source IP address of requests &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2503&quot;&gt;#2505&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A few documentation updates, including a clarfication on how to run the Device Agent under docker &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2498&quot;&gt;#2498&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.9.3.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-3-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go the the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/influxdb-historical-data/</id>
        <title>Creating a Historical Data Dashboard with InfluxDB and Node-RED</title>
        <summary>Detailed instructions on how to create a Node-RED dashboard that shows historical data.</summary>
        <updated>2023-07-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/influxdb-historical-data/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Every new dashboard is met with the fast-following request, “can we save this data and somehow look back on it?”  Yes, you can, and let’s use InfluxDB to make it happen!&lt;/p&gt;
&lt;p&gt;Edge devices are often polling sensors at regular intervals and are a perfect candidate to be paired with a database purpose-built for time-series data, like InfluxDB.  Let’s capture some data, create a live chart, store the data, and then create a GUI for retrieving the data.&lt;/p&gt;
&lt;p&gt;Here’s a screenshot of the dashboard we will create, which is divided into two sections. The first section displays live data, while the second section consists of fields that enable users to query the database and retrieve historical data.  Looking at the live data, the chart depicts a sinusoidal graph that represents the scale measurements used for quality assurance in the aggregate production process at an automated mining operation. The graph showcases fluctuations in weight over time, indicating variations in the samples being weighed. This monitoring process ensures the quality and consistency of the aggregates being produced.  The historical data shows a snippet of this information that was retrieved from InfluxDB.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the historical dashboard&quot; alt=&quot;&amp;quot;Screenshot showing the historical dashboard&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Here is a screenshot of the simple Node-RED flow to create that dashboard.  We will dive into the details through this article, and, by the end, you will be able to create this flow yourself.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the historical dashboard flow&quot; alt=&quot;Screenshot showing the historical dashboard flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;capturing-serial-port-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/#capturing-serial-port-data&quot;&gt;Capturing serial port data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The live view is fed by data coming from a simple scale with a serial interface.  This &lt;a href=&quot;https://www.brecknellscales.com/wp-content/uploads/2022/09/LPS-Series_u_en_fr_501724-1.pdf&quot;&gt;Brecknell LPS-150&lt;/a&gt; scale will auto power-on, remembers the last tare setting, and continuously sends its reading via RS-232, so it is a great unit to use for unattended IoT projects.&lt;/p&gt;
&lt;p&gt;On the Node-RED side, a serial node can be configured to capture this incoming data.  If your device running Node-RED doesn’t have an RS-232 port, there are many variations of RS-232-to-USB cables to help you connect.  This scale is sending data at a very high-speed interval so it is important to use a “delay” node before the rest of your flow gets bogged down.&lt;/p&gt;
&lt;p&gt;Below, I have configured the serial port node with the same settings that were used to set up the scale. These settings are commonly documented as &amp;quot;9600 8N1&amp;quot; in shorthand.  In serial communication it is necessary for the two devices to have the exact same settings or the data becomes garbled.  The incoming stream of ASCII text is divided using the hex value 0x0D, which corresponds to the return character. This character is used as a delimiter to separate the individual chunks of text within the incoming data stream.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the serial port node config&quot; alt=&quot;&amp;quot;Screenshot showing the serial port node config&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/serial-port-node-3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;With this “delay” node, we now have a new message from the scale at a rate of 1 msg per 5 seconds&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the delay node properties tab&quot; alt=&quot;&amp;quot;Screenshot showing the delay node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/delay-4.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;The debugger allows us to see the raw data as it is captured.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Debugger&quot; alt=&quot;&amp;quot;Debugger&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/debugger-5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Unfortunately, these values are not in a friendly form to work with.  Ideally, we want our payload to just be a number, not this string with odd characters, extra spaces, and the units.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the change node setting payload&quot; alt=&quot;&amp;quot;Screenshot showing the change node setting payload&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-6.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
 &lt;br /&gt;
&lt;p&gt;We need to extract the numeric part of the string using a regular expression with a “change” node and the JSONata expression $number($match(msg.payload,  /-?(&#92;d+(.&#92;d+)?)/ , 10).match).  “$match” and “/-?(&#92;d+(.&#92;d+)?)/” help the function pull out the numeric components of the string and “$number” parses these components to be an actual number data type.&lt;/p&gt;
&lt;p&gt;Here are the properties of the “change” node.&lt;/p&gt;
&lt;p&gt;When we look in the debugger we see the payload specified as a “number” and the value displayed in blue, both indications that we have successfully extracted the weight as the correct data type.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the output type in the debug panel&quot; alt=&quot;&amp;quot;Screenshot showing the output type in the debug panel&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/number-7.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting-up-serverless-influxdb-in-the-cloud&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/#setting-up-serverless-influxdb-in-the-cloud&quot;&gt;Setting up serverless InfluxDB in the cloud&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we have some live data, let’s store it using InfluxDB. Below are the steps to set up an account with the InfluxDB free service.  Navigate to &lt;a href=&quot;https://www.influxdata.com/products/influxdb-overview/&quot;&gt;https://www.influxdata.com/products/influxdb-overview/&lt;/a&gt; and let’s begin.  Click on “Get Started for Free” under Cloud, InfluxDB Cloud Serverless.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Influxdb cloud &#39;Getting started&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the Influxdb cloud &#39;Getting started&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/run-influxdb-8.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For this example the Free plan will work fine.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the influxdb cloud tiers&quot; alt=&quot;&amp;quot;Screenshot showing the influxdb cloud tiers&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/free-influxdb-9.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Create a bucket to store the data.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the &#39;Go to buckets&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Go to buckets&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/bucket-influxdb-10.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the &#39;Create Bucket&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Create Bucket&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/load-data-influxdb-11.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Generate a token to direct the calls from Node-RED to your InfluxDB account when they hit the InfluxDB server:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the &#39;Genrate token&#39; button&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;Genrate token&#39; button&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/token-influxdb-12.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;I selected “Generate All Access API Token,” but eventually you will want a custom, more restricted approach.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the &#39;prompt&#39; asing to enter the description for token&quot; alt=&quot;&amp;quot;Screenshot showing the &#39;prompt&#39; asing to enter the description for token&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/generate-token-influxdb-13.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Copy your token and do not share it!  (mine will be deleted later)&lt;/p&gt;
&lt;h2 id=&quot;connecting-node-red-to-influxdb&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/#connecting-node-red-to-influxdb&quot;&gt;Connecting Node-RED to InfluxDB&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Navigate to “Manage Palette” in the Node-RED hamburger menu in the upper right corner of the flow editor.  I did a search for InfluxDB and selected the most popular one, “node-red-contrib-influxdb” by looking at the number of downloads per week at &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-influxdb&quot;&gt;https://flows.nodered.org/node/node-red-contrib-influxdb&lt;/a&gt;.  When you are just starting out, it can be a smart decision to go with the popular option. The popularity indicates a level of trust and adoption within the community, making it a reliable choice for beginners&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the influxdb node in the manage palette&quot; alt=&quot;&amp;quot;Screenshot showing the influxdb node in the manage palette&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/install-contrib-influxdb-14.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;After installing this package you will see three new nodes in your flow editor.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the installed influxdb nodes in the palette&quot; alt=&quot;Screenshot showing the installed influxdb nodes in the palette&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-nodes-15.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Drag and drop the “influxdb out” node into your flow, double click on it, and start filling out the needed fields.  The naming convention of “test&amp;lt;&lt;THING&gt;&amp;gt;” works well for initial setups to make it clear what names should go where.&lt;/THING&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the influxdb-out node config&quot; alt=&quot;&amp;quot;Screenshot showing the influxdb-out node config&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-out-node-16.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt; 
&lt;p&gt;It was a little unclear what URL to use with this serverless option, but I guessed it was the same as the URL for the InfluxDB resource center account page, “&lt;a href=&quot;https://us-east-1-1.aws.cloud2.influxdata.com/&quot;&gt;https://us-east-1-1.aws.cloud2.influxdata.com/&lt;/a&gt;” and it worked.  Then, enter the API token that was generated earlier.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;image_tooltip&quot; alt=&quot;&amp;quot;image_tooltip&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-node-17.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;The “influxdb out” node is now ready to start storing payloads.  The documentation for the InfluxDB nodes at &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-influxdb&quot;&gt;https://flows.nodered.org/node/node-red-contrib-influxdb&lt;/a&gt; gives more detail as to extra options, such as tags, that you might want to attach to your data being stored.  In this simple example, we are just going to send the “influxdb out” node a number via the msg.payload.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the flow sending data to InfluxDB and to a dashboard chart widget&quot; alt=&quot;Screenshot showing the flow sending data to InfluxDB and to a dashboard chart widget&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-influxdb-out-18.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Here is a chart of the live data which is also being stored.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the dashboard with live data chart&quot; alt=&quot;&amp;quot;Screenshot showing the dashboard with live data chart&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/live-data-chart-19.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt; 
&lt;p&gt;The InfluxDB Data Explorer helps you create a SQL call and allows you to run it right in the browser so you can verify that your data is being stored correctly.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the InfluxDB Explorer&quot; alt=&quot;&amp;quot;Screenshot showing the InfluxDB Explorer&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/influxdb-explorer-20.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;h2 id=&quot;creating-a-historical-data-gui&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/#creating-a-historical-data-gui&quot;&gt;Creating a historical data GUI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we have our data being stored, but we aren’t quite finished. We still want an easy way to pull this information up and for it to be presented in a chart, just like the live data.&lt;/p&gt;
&lt;p&gt;Here is the Dashboard group we will create for this GUI.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the GUI for historical data&quot; alt=&quot;&amp;quot;Screenshot showing the GUI for historical data&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/historical-data-21.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;And here is the flow to create it.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the flow of historical data GUI&quot; alt=&quot;&amp;quot;Screenshot showing the flow of historical data GUI.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/data-flow-22.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;A “template” node creates a convenient way to create a plain text output with variable properties within.  Below you can see that &lt;code&gt;msg.query&lt;/code&gt; is created from a string of text with “rangeStart” and “rangeEnd” dynamically inserted using the “mustache” syntax.  More information about how to query InfluxDB can be found here:  &lt;a href=&quot;https://docs.influxdata.com/influxdb/v2.0/query-data/get-started/query-influxdb/&quot;&gt;https://docs.influxdata.com/influxdb/v2.0/query-data/get-started/query-influxdb/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the template node&quot; alt=&quot;&amp;quot;Screenshot showing the template node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/template-node-23.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Using the &amp;quot;Form&amp;quot; dashboard node is an easy way to collect all the required information for our query. We need to be able to enter in a date and time to start gathering the data, and a window to know how long a range of values to pull.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the form widget&quot; alt=&quot;&amp;quot;Screenshot of the form widget&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/form-node-24.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Here is the code from the “time/date” function node.  A bit of juggling of local time versus UTC time is needed to allow the user to intuitively query the correct data for their timezone.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the function node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the function node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/function-node-25.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt; 
&lt;p&gt;Here is the “change” node used to create the msg.rangeEnd.  The JSONatta expression is &lt;code&gt;$fromMillis($toMillis(msg.rangeStart) + msg.payload.window * 60 * 1000)&lt;/code&gt;.  The expression combines the milliseconds from the &lt;code&gt;msg.rangeStart&lt;/code&gt; with the calculated milliseconds in the “Window (minutes)” from the GUI.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the change node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the change node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-26.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;Now that the query is coming back from InfluxDB, let’s break down how to transform this data object into one that can be read by the “chart” node.  Below, we see on the left column what the object looks like from InfluxDB and on the right we see how it must be structured to be viewed in the chart.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the formated data in the debug panel&quot; alt=&quot;&amp;quot;Screenshot showing the formated data in the debug panel&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/data-format-27.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Rob Marcer has a great article on working with persistent chart data found here: &lt;a href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/&quot;&gt;/blog/2023/05/persisting-chart-data-in-node-red/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can use a series of nodes from the Node-RED core package to transform this data.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the flow to transform the data&quot; alt=&quot;&amp;quot;Screenshot showing the flow to transform the data&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/transform-data-28.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;First, a “switch” node is used to determine if the response InfluxDB contains any data so that we can either format the data properly, or clear the chart and indicate “No Data.”&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the switch node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the switch node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/switch-node-28.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt; 
&lt;p&gt;The “Label” field in the “chart” node can also be dynamically created with the mustache syntax.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the chart widget setting label dynamically&quot; alt=&quot;&amp;quot;Screenshot of the chart widget setting label dynamically&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/chart-node-29.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt; 
&lt;p&gt;If the “is not empty” “switch” node sees an empty payload, this “change” node sets the payload to an empty array, clearing the chart, and sets the &lt;code&gt;msg.title&lt;/code&gt; to “No Data” so users know their query, though successful, returned an empty set of values.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the change node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the change node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-30.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;The parameters for the “split” node can be left as-is.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the split node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the split node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/split-node-31.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;In the “chartData” “change” node, will pull out the two values we need for the chart, milliseconds since the UNIX epoch for the x-value and the measurement from the scale for the y-value.  A simple JSONatta expression helps us transform the date from a string to milliseconds for the x-value.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the change node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the change node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-32.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;The “join” node just needs to be set to “Combine each” msg.chartData object and configured “to create” an array.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the join node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the join node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/join-node-33.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;The final “change” node, “format,” is where we prescribe the format needed for the “chart” node, [{&amp;quot;series&amp;quot;:[&amp;quot;&amp;quot;],&amp;quot;data&amp;quot;:[[]],&amp;quot;labels&amp;quot;:[&amp;quot;&amp;quot;]}], and finally we insert our &lt;code&gt;msg.chartData&lt;/code&gt; array into that structure.  Notice &lt;code&gt;msg.title&lt;/code&gt; is now set to “Data Received.”&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the change node properties tab&quot; alt=&quot;&amp;quot;Screenshot of the change node properties tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/change-node-33.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;And, there you have it.  You can query the same range of data found on the live chart to ensure the code is working and then you can use the dashboard to pull up historical data, way in the past from what is shown on the live chart.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the dashboard showing the historical and live data chart&quot; alt=&quot;&amp;quot;Screenshot of the dashboard showing the historical and live data chart&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/final-dashboard-34.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Your current version is clear and concise—great for a blog or call-to-action section. Here&#39;s a slightly refined version with improved flow, punctuation, and tone for polish, while keeping the structure intact:&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/influxdb-historical-data/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You’ve successfully built a powerful dashboard that captures real-time data and stores it in InfluxDB for historical analysis. This setup provides valuable insights into your process data and helps identify trends over time.&lt;/p&gt;
&lt;p&gt;If you are planning to run this dashboard in production, a few important questions may come to mind: How do you ensure it runs reliably 24/7? How do you deploy it to other locations? What happens if someone accidentally breaks the flow?&lt;/p&gt;
&lt;p&gt;This is where &lt;strong&gt;FlowFuse&lt;/strong&gt; comes in. It takes your existing Node-RED flows and adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automatic backups and instant recovery&lt;/li&gt;
&lt;li&gt;Easy deployment to multiple locations&lt;/li&gt;
&lt;li&gt;Version control for safe and trackable updates&lt;/li&gt;
&lt;li&gt;Team collaboration without conflicts&lt;/li&gt;
&lt;li&gt;Remote instance management—and much more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your flows continue to work just as they are—FlowFuse simply makes them production-ready.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Try FlowFuse free for 30 days&lt;/a&gt; and see how it transforms Node-RED into a scalable, enterprise-ready platform.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/</id>
        <title>How to Deploy a Basic OPC-UA Server in Node-RED - Part 1</title>
        <summary>OPC-UA Server Information Modeling in Node-RED</summary>
        <updated>2023-07-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This article is the first part of a series of OPC-UA content.  Here, we will explain some basic concepts of OPC-UA as they apply to building a server in Node-RED, then walk through and deploy an example OPC-UA Server.&lt;/p&gt;
&lt;h2 id=&quot;what-is-opc-ua%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/#what-is-opc-ua%3F&quot;&gt;What is OPC-UA?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open Platform Communications Unified Architecture (OPC UA) is an open, platform independent communication framework frequently utilized in industrial automation, and is considered one of the key protocol standards for Industry 4.0 and Industrial IoT (IIoT).  The standard is developed and maintained by a consortium called the OPC Foundation, with recognizable industry names such as Siemens, Honeywell, Microsoft, Beckhoff, SAP, Yokogawa, ABB, Rockwell, and Schneider Electric.&lt;/p&gt;
&lt;p&gt;Because of OPC-UA’s wide industry acceptance, it is increasingly becoming natively supported on devices and systems spanning the entirety of the automation pyramid.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Automation Pyramid&quot; alt=&quot;&amp;quot;Automation Pyramid&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/automation-pyramid.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image reference - &lt;a href=&quot;https://www.motioncontroltips.com/what-is-opc-ua-and-how-does-it-compare-with-industrial-ethernet/&quot;&gt;imagecontroltips.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;fieldbus-model-vs-opc-ua-information-model&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/#fieldbus-model-vs-opc-ua-information-model&quot;&gt;Fieldbus Model vs OPC-UA Information Model&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of today, industrial ethernet fieldbuses dominate the field/device-level (level 0) and controller/PLC-level (level 1) of the automation pyramid.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;OPC-UA Pyramid&quot; alt=&quot;&amp;quot;OPC-UA Pyramid&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/OPC-UA-pyramid-2.webp&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image reference - &lt;a href=&quot;https://www.mdpi.com/1424-8220/21/14/4656&quot;&gt;mdpi.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Fieldbuses such as Profinet, Ethernet/IP, and EtherCAT, employ deterministic, real-time communication, which is essential for mission-critical and safety-oriented automation tasks.  OPC-UA is most commonly encountered at the SCADA level and above (level 2-4).  However, with the inclusion of &lt;a href=&quot;https://www.tttech-industrial.com/resource-library/blog-posts/opc-ua-fx&quot;&gt;Time Sensitive Networking (TSN) into the OPC-UA technology stack&lt;/a&gt;, OPC-UA can be feasibly used for real-time communication all the way down to the device level.&lt;/p&gt;
&lt;p&gt;Traditionally, fieldbus protocols transmit only raw data from field devices (ie, a float to represent a pressure, or a boolean to represent the position of a switch).  The fieldbus data gets pushed up the automation stack layer by layer, where eventually it will be converted to a format suitable for IT systems to consume (such as OPC-UA).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Fieldbus Model&quot; alt=&quot;&amp;quot;Fieldbus Model&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/fieldbus-model.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In contrast to fieldbus protocols, OPC-UA represents automation data in the form of nodes. The framework for constructing nodes is referred to as the &lt;a href=&quot;lhttps://reference.opcfoundation.org/Core/Part5/v104/docs/&quot;&gt;OPC Information model&lt;/a&gt;, and consists of pre-defined classes and methods that are programmed in the OPC Server address space.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;OPC Information Model&quot; alt=&quot;&amp;quot;OPC Information Model&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-information-model.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Devices can be described as objects that give a holistic view of the device, beyond simply the raw value.  To construct a device object, we can take different individual attributes associated with a device, such as the transmitter raw value, transmitter fault flag, alarm setpoint, and combine them, similar to how user-defined datatypes (UDTs) are objects used to represent devices in PLCs.  The information model also defines a folder structure, to allow devices information to reside in a structured hierarchy.  Using the example temperature transmitter above, an example folder structure can be constructed as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/Root/Objects/Calcinator 1 PLC/Temperature Transmitters/Tank 1 Temperature/Transmitter Value&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This folder structure will be exposed via the OPC Client browser, allowing end-users to easily “drill down” to individual node information in a logical manner.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;OPC Information Model&quot; alt=&quot;&amp;quot;OPC Client Browser&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-client-browser.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
In summary, OPC-UA represents a trade-off between complex information modeling, with the versatility for that data to be consumed by devices and systems all the way up the automation pyramid layers.  The data does not have to pass through subsequent automation layers on the way up, nor does the data need to undergo any conversion along the way.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;OPC-UA Distributed Model&quot; alt=&quot;&amp;quot;OPC-UA Distributed Model&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/OPC-UA-distributed-model.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
&lt;em&gt;Image reference - &lt;a href=&quot;https://ifr.org/post/faster-robot-communication-through-the-opc-robotics-companion-specification&quot;&gt;ifr.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The OPC client simply needs to subscribe to the OPC Server endpoint url (ex. opc.tcp://server.address), and the client will be able to browse the structured OPC data as it’s modeled in the server.  Any client will receive the information in the same manner, regardless if it’s a PLC, SCADA, MES, or ERP system.  This opens the possibility for horizontal and vertical system integration in a standardized manner. Additionally, the more information that is exposed about a device, the easier it is to track, and use said data to autonomously reconfigure, or pre-emptively take maintenance actions.&lt;/p&gt;
&lt;h2 id=&quot;deploying-an-example-opc-ua-server-in-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/#deploying-an-example-opc-ua-server-in-node-red&quot;&gt;Deploying an Example OPC-UA Server in Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With some background on OPC-UA and how information is modeled in mind, we can take a look at the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua-server&quot;&gt;node-red-contrib-opcua-server&lt;/a&gt; node, which is merely a compact version of the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;node-red-contrib-opcua&lt;/a&gt; node that only focuses on the OPC-UA server and hence requires less dependencies.&lt;/p&gt;
&lt;p&gt;An &lt;a href=&quot;https://github.com/BiancoRoyal/node-red-contrib-opcua-server/blob/master/examples/server-with-context.json&quot;&gt;example flow&lt;/a&gt; is provided on github that can serve as a basis for understanding how a OPC-UA server is constructed.  Let’s get the example server up and running.&lt;/p&gt;
&lt;p&gt;Deploying the example flow yields the following result -&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Compact Server Flow&quot; alt=&quot;Compact Server Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-server-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an inject node is trigging the function &lt;code&gt;set flow context Inputs&lt;/code&gt; at a one second interval, which creates 7 randomly generated float values and stores them as flow context variables, &lt;code&gt;isoInput2&lt;/code&gt; - &lt;code&gt;isoInput8&lt;/code&gt; (isolated inputs).  The values will change to a new random number each time the node is injected.&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-73&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-73&quot; class=&quot;language-javascript&quot;&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput3&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput4&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput5&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput6&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput7&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoInput8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-73&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;another inject node is triggering the function &lt;code&gt;set flow context Outputs&lt;/code&gt;, also at a one second interval, which creates another set of 7 randomly generated float values and stores them as flow context variables, &lt;code&gt;isoOutput2&lt;/code&gt; - &lt;code&gt;isoOutput8&lt;/code&gt; (isolated inputs).  The values will change to a new random number each time the node is injected.&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-81&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-81&quot; class=&quot;language-javascript&quot;&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput3&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput4&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput5&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput6&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput7&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;flow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;isoOutput8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-81&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We can confirm the values are being stored in memory by checking the flow context data and pressing the refresh button.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Context Data option&quot; alt=&quot;&amp;quot;Screenshot showing the Context Data option&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/context-data-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the flow variables in the context data tab&quot; alt=&quot;Screenshot showing the flow variables in the context data tab&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/context-data-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Each time we hit refresh, the values change, confirming that the values are randomly changing every second.&lt;/p&gt;
&lt;p&gt;The last, and most important part of the flow, is the &lt;code&gt;Compact-Server&lt;/code&gt; node, which actually stands alone without any incoming or outgoing connections.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Compact Server Node&quot; alt=&quot;&amp;quot;Compact Server Node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-server-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
In the &lt;code&gt;Compact-Server&lt;/code&gt; node properties, the first tab is &lt;code&gt;Settings&lt;/code&gt;, and the two important properties here are &lt;code&gt;Port&lt;/code&gt; and &lt;code&gt;Show Errors&lt;/code&gt;.  As can be seen in the node screenshot above, the node is reporting &lt;code&gt;active&lt;/code&gt;, which means the server is configured correctly.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Settings Tab of compact server node&quot; alt=&quot;Screenshot showing the Settings Tab of compact server node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/settings-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Limits&lt;/code&gt; tab specifies some default limits that we can configure if we like, but are not necessary to be modified for test purposes.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Security&lt;/code&gt; tab has one important option, &lt;code&gt;Allow Anonymous&lt;/code&gt;.  By default, anonymous access is enabled.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Security Tab of compact server node&quot; alt=&quot;Screenshot showing the Security Tab of compact server node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/security-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
For a production system, we will want to enable security, but for test purposes, we will leave anonymous access enabled.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Users &amp;amp; Sets&lt;/code&gt; tab is related to security and permissions.  We can leave this empty for testing.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Address Space&lt;/code&gt; tab is where our server OPC Information Model is constructed, using classes and methods from the &lt;a href=&quot;https://node-opcua.github.io/&quot;&gt;node-opcua sdk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Breaking down the provided example code for further context, it starts with a function that is responsible for invoking the OPC-UA server,&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-118&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-118&quot; class=&quot;language-javascript&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; opcua &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; coreServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;choreCompact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;opcua&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-118&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;and then the namespace is created.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-122&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-122&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; namespace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; addressSpace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnNamespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-122&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Further down, the variables that will be published by the server (which are our &lt;code&gt;isoInput&lt;/code&gt; &amp;amp; &lt;code&gt;isoOutput&lt;/code&gt; flow context variables) are initialized,&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-126&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-126&quot; class=&quot;language-javascript&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;isoInput1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    flexServerInternals&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;isoInput1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50.0&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;isoInput2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;isoInput3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-126&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;and an OPC folder structure is defined.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-130&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-130&quot; class=&quot;language-javascript&quot;&gt;  coreServer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debugLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;init dynamic address space&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rootFolder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; addressSpace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;RootFolder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;construct new address space for OPC UA&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myDevice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; namespace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFolder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rootFolder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;objects&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;browseName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RaspberryPI-Zero-WLAN&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-130&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Then, with our variables and folder structure defined, nodes are added to the namespace for each context variable.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-134&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-134&quot; class=&quot;language-javascript&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; gpioDI1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; namespace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;organizedBy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; isoInputs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;browseName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;I1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;nodeId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ns=1;s=Isolated_Input1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;dataType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Double&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Variant&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string-property property&quot;&gt;&quot;dataType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DataType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Double&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string-property property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; flexServerInternals&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;isoInput1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&quot;set&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        flexServerInternals&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sandboxFlowContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string&quot;&gt;&quot;isoInput1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;variant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; opcua&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StatusCodes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Good&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-134&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Last, OPC views are defined.  Views create custom hierarchies our OPC Client can browse as an alternative to the default folder structure.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-138&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-138&quot; class=&quot;language-javascript&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; viewDI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; namespace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;organizedBy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rootFolder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;views&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;browseName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RPIW0-Digital-Ins&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; viewDO &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; namespace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;organizedBy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rootFolder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;views&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;browseName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RPIW0-Digital-Outs&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  viewDI&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addReference&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;referenceType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Organizes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string-property property&quot;&gt;&quot;nodeId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; gpioDI1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodeId&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-138&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Finally, on the &lt;code&gt;Discovery&lt;/code&gt; tab, we must define an endpoint for an OPC Client to subscribe to.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Endpoint Url&lt;/code&gt; follows the format &lt;code&gt;opc.tcp://&amp;lt;address&amp;gt;:port&lt;/code&gt;.  Our port was defined on the &lt;code&gt;Settings&lt;/code&gt; tab, which by default, is port &lt;code&gt;54845&lt;/code&gt;. The address will be either the url or ip address of your Node-RED instance.  In my case, it’s 192.168.0.114.  So my Endpoint Url = &lt;code&gt;opc.tcp://192.168.0.114:54845&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Discovery Tab of compact server node&quot; alt=&quot;Screenshot showing the Discovery Tab of compact server node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/discovery-tab.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Once the endpoint url is added, deploy the flow, and confirm the server is reporting “active”.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Active Tab of compact server node&quot; alt=&quot;Screenshot showing the Active Tab of compact server node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-server-active.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;connect-to-example-opc-server-using-opc-ua-browser&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/#connect-to-example-opc-server-using-opc-ua-browser&quot;&gt;Connect to Example OPC-Server Using OPC-UA Browser&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To connect to our OPC endpoint, we need an OPC Client.  Prosys provides a &lt;a href=&quot;https://www.prosysopc.com/products/opc-ua-browser/&quot;&gt;free OPC-UA Browser &lt;/a&gt;that supports Windows, Linux, and Mac OS.  To test our Server, the Windows version of Prosys OPC-UA Browser will be utilized.&lt;/p&gt;
&lt;p&gt;To connect to our Node-RED OPC server, enter the endpoint url and press “connect to server”.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the OPC Client&quot; alt=&quot;&amp;quot;Screenshot showing the OPC Client&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-client-connect.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
It will ask for security.  Remember that we allowed anonymous access, so the default security mode of &lt;code&gt;None&lt;/code&gt; is the correct option.&lt;/p&gt;
&lt;p&gt;Once connected, we can browse our OPC Server.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;OPC Client UI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-client-ui.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
If we navigate to &lt;code&gt;Objects → RaspberryPI-Zero-WLAN → GPIO → Inputs&lt;/code&gt;, we can see a list of inputs that correspond to the &lt;code&gt;isoInput&lt;/code&gt; context variables defined in the example flow, which are randomly generated numbers.&lt;/p&gt;
&lt;p&gt;Clicking &lt;code&gt;I1&lt;/code&gt; we can see the value in real-time, along with some additional properties.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;OPC Client Node&quot; alt=&quot;OPC Client Node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-client-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
If we go to &lt;code&gt;Views&lt;/code&gt;, we can see the custom hierarchy defined in the example server, which divides the data by Digital-Ins and Digital-Outs.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;OPC Client View&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/opc-client-view.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/how-to-deploy-a-basic-opc-ua-server-in-node-red/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this article, we compare OPC-UA to traditional fieldbus protocols, explain the importance of the OPC UA Information Model to understand how data is modeled in the address space of an OPC Server, and then walk through and deploy an example compact OPC-UA Server flow.&lt;/p&gt;
&lt;p&gt;In our next article, we will build a custom OPC-UA Server in Node-RED with data pulled from an Allen Bradley PLC over Ethernet/IP, using the PLC data to develop a custom OPC UA Information Model programmed in the OPC server address space.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/community-news-07/</id>
        <title>Community News July 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-07-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/community-news-07/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for July 2023, a monthly roundup of what’s been happening with FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;new-release&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#new-release&quot;&gt;New Release&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last week we released FlowFuse 1.9, featuring new API documentation available in the Swagger UI and the ability to customize Node-RED palettes.&lt;/p&gt;
&lt;p&gt;Read about the details of FlowFuse 1.9 in our &lt;a href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/&quot;&gt;release announcement&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;how-to-deploy-node-red-to-hundreds-of-plcs-and-iot-edge-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#how-to-deploy-node-red-to-hundreds-of-plcs-and-iot-edge-devices&quot;&gt;How to deploy Node-RED to hundreds of PLCs and IoT edge devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our next webinar will be focused on the device management capabilities in the FlowFuse platform. Lots of companies are deploying Node-RED to PLCs and IIoT edge computers. FlowFuse allows these companies to scale and manage Node-RED deployment out to hundreds of these types of devices. Discover how during our next webinar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/flowforge-device-management/&quot;&gt;Sign-up today&lt;/a&gt; to join us on July 27.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog-and-documentation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#from-our-blog-and-documentation&quot;&gt;From our Blog and Documentation&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/&quot;&gt;The Next Step in Data Visualization - Announcing the Successor to the Node-RED Dashboard&lt;/a&gt; - FlowFuse announces plans to develop the next version of the Node-RED Dashboard project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/&quot;&gt;Node-RED as a No-Code Ethernet/IP to S7 Protocol Converter&lt;/a&gt; - A guide to using Node-RED for converting ethernet IP data to Siemens S7.  Also a &lt;a href=&quot;https://youtu.be/dteXgcBXUnk&quot;&gt;video version&lt;/a&gt; of the same content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/mqtt/&quot;&gt;MQTT and its Role in IoT and Industrial IoT&lt;/a&gt; - A practical explainer on the role of MQTT in IoT use cases and how to connect with an MQTT broker in Node-RED.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Two new Node-RED Nodes Explained articles&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/split/&quot;&gt;Nodes explained: Split&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/filter/&quot;&gt;Nodes explained: Filter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/1GKkXJOQMhU&quot;&gt;Node-RED &amp;amp; Industry 4.0: The Future is Now&lt;/a&gt; - An informative panel discussion led by Walker Reynolds on the role of Node-RED in the future of Industry 4.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.openmindmap.org/blog/node-red-terminology/&quot;&gt;Node-RED Terminology&lt;/a&gt; - An explanation of the different Node-RED terminology.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/community-news-07/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;Contract Front-End Engineer – Node-RED Dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/07/flowforge-1-9-release/</id>
        <title>FlowFuse now offers API Documentation with Swagger UI</title>
        <summary>FlowFuse 1.9 adds new features to make it easier to administer FlowFuse</summary>
        <updated>2023-07-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/07/flowforge-1-9-release/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 1.9 adds new features to make it easier to administer FlowFuse platform deployments, including new API documentation and the ability to create customized Node-RED palettes.&lt;/p&gt;
&lt;h2 id=&quot;api-documentation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#api-documentation&quot;&gt;API Documentation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse API allows developers to programmatically interact with the FlowFuse platform. This makes it possible to integrate FlowFuse into different infrastructure technologies, create scripts to automate specific FlowFuse tasks and embed FlowFuse into other applications.&lt;/p&gt;
&lt;p&gt;In the 1.9 release we are now publishing our &lt;a href=&quot;https://flowfuse.com/docs/api/&quot;&gt;API documentation&lt;/a&gt; using the &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;OpenAPI specification&lt;/a&gt; and making it viewable with the Swagger UI. Both these industrial standards will make using the FlowFuse API easier to use and understand.&lt;/p&gt;
&lt;h2 id=&quot;customize-node-red-palettes-%232002&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#customize-node-red-palettes-%232002&quot;&gt;Customize Node-RED Palettes  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2002&quot;&gt;#2002&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse platform adminstrators are now able to create customized Node-RED palettes that will be used when a Node-RED instance is created. An adminstator can create pre-defined templates to specify the nodes that should be included in the palette. This makes it easier for FlowFuse teams to standardized on Node-RED usage across an organization.&lt;/p&gt;
&lt;p&gt;Note: this feature is not available for FlowFuse cloud users since they do not have administrator access.&lt;/p&gt;
&lt;h2 id=&quot;new-rbac-role-for-dashboard-users-%232292&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#new-rbac-role-for-dashboard-users-%232292&quot;&gt;New RBAC Role for Dashboard users &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1924&quot;&gt;#2292&lt;/a&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A new FlowFuse user role has been created to view Node-RED dashboards. This allows for users to view Nod-RED dashboards without access to the Node-RED editor or requiring separate login credentials.&lt;/p&gt;
&lt;h2 id=&quot;other-new-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#other-new-features&quot;&gt;Other New Features&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;FlowFuse device agent is now supported on Windows &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/78&quot;&gt;#78&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Allow local configuration of https/httpStatic on a device &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/110&quot;&gt;#110&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Implementing custom certificate settings for device configuration &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2257&quot;&gt;#2257&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Allow devices to access the &amp;quot;Snapshot ID&amp;quot; and the &amp;quot;Snapshot Name&amp;quot; running on them &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/94&quot;&gt;#94&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;High Availability logging enhanced: Individual Node-RED Instance replica querying and filtering &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2260&quot;&gt;#2260&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;High Availability is now generally available &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2412&quot;&gt;#2414&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Can not promote NR instance in DevOps Pipeline  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2363&quot;&gt;#2363&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Billing team menu item missing on first page load &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2398&quot;&gt;#2398&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Duplicate labels in Instance Import dialog &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2200&quot;&gt;#2200&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Broken littie animations &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2354&quot;&gt;#2354&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Instance Logs page doesn&#39;t handle errors well &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1083&quot;&gt;#1083&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Device continues to run edited flows once taken out of dev mode &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2323&quot;&gt;#2323&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Device Editor cannot pickup FF theme &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/89&quot;&gt;#89&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;community-contributions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#community-contributions&quot;&gt;Community Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to our community members for their contributions to this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sumitshinde-84 - make Instance and application names in delete popup easily selectable &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2291&quot;&gt;#2291&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;biancode - Fixed typo in doc  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/2327&quot;&gt;#2327&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.9.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/07/flowforge-1-9-release/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go the the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/dashboard-announcement/</id>
        <title>The Next Step in Data Visualization - Announcing the Successor to the Node-RED Dashboard</title>
        <summary>FlowFuse&#39;s Journey Towards a New Node-RED Dashboard</summary>
        <updated>2023-06-21T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/dashboard-announcement/"/>
        <author><name></name></author>
        <author><name></name></author>
        <content type="html">&lt;p&gt;For the past several years, the Node-RED Dashboard has been an indispensable tool for many Node-RED users. It has offered a seamless way to create live dashboards, enabling the quick and intuitive creation of user interfaces for Node-RED flows. However, as the saying goes, &amp;quot;all good things must come to an end.&amp;quot;
We at FlowFuse have identified a significant need for a modern, interactive data visualization and dashboard solution. Having evaluated a wide range of options, we&#39;ve decided to embark on an exciting journey: the creation of what we hope becomes the official successor to the Node-RED Dashboard.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-at-hand&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/#the-problem-at-hand&quot;&gt;The Problem at Hand&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The original Node-RED Dashboard is based on Angular v1, which is no longer maintained. Although small patches have been and will continue to be applied on a &amp;quot;best can do&amp;quot; basis, there will be no major feature upgrades. The lack of ongoing maintenance and updates has the potential to lead to underlying security breakages, a risk we are not comfortable taking. We have recognized the need to innovate and adapt, which is why we are creating a completely new project to replace the existing Node-RED Dashboard.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/#the-solution&quot;&gt;The Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The successor to the Node-RED Dashboard will be a completely new project, published as a separate package. This new project will take the reins from the old dashboard and guide us into the future with the support and blessing of the existing dashboard maintainers. The Node-RED community can rest assured that the project will stay under the Apache 2.0 licence and keep intact the core principles of open-source and community-driven development.&lt;/p&gt;
&lt;h2 id=&quot;community-involvement-and-open-source-contribution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/#community-involvement-and-open-source-contribution&quot;&gt;Community Involvement and Open Source Contribution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We believe in the power of the community, and we want your feedback. If there are features you&#39;d like to see or improvements you think can be made, we invite you to open a &lt;a href=&quot;https://github.com/FlowFuse/node-red-dashboard/issues/new/choose&quot;&gt;Github issue&lt;/a&gt;. Your insights and suggestions will be invaluable in shaping the future of this project. Contributions from the community are not just welcome, but highly encouraged. We believe that the strength of a project is proportional to the strength of its community.&lt;/p&gt;
&lt;p&gt;In our commitment to transparency and collaboration, we will be documenting all major decision-making processes and sharing the details here in our blog as they become available. By working closely with additional Node-RED key figures like Dave Conway-Jones, and by making our development process as open and collaborative as possible, we aim to ensure that the successor to the Node-RED Dashboard lives up to the high standards set by the original, while also introducing innovative features and enhancements.&lt;/p&gt;
&lt;h2 id=&quot;join-the-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/#join-the-team&quot;&gt;Join the Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Are you a developer looking for a new challenge? We are searching for a freelancer to help us with the development of the first version of the new dashboard. This is a 2-3 month project that provides an exciting opportunity to contribute to the future of data visualization and Node-RED. If you&#39;re interested, &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4911532004&quot;&gt;we&#39;d love to hear from you.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;charting-the-course&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/dashboard-announcement/#charting-the-course&quot;&gt;Charting the Course&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As we embark on this new journey, we are excited about the potential of the successor to the Node-RED Dashboard. The road ahead will be filled with challenges, but we are confident that with the help of the community, and a dedicated team, we will create a tool that surpasses its predecessor in every way.&lt;/p&gt;
&lt;p&gt;Join us on this exciting journey as we innovate, create, and redefine the future of data visualization with the successor to the Node-RED Dashboard.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/</id>
        <title>Node-RED as a No-Code EtherNet/IP to S7 Protocol Converter</title>
        <summary>Beginner tutorial for using Node-RED as free industrial protocol converter</summary>
        <updated>2023-06-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Frequently in industrial automation, there&#39;s a need for two devices that use different protocols to communicate with each other, requiring protocol conversion.&lt;br /&gt;
In this tutorial, we present a mock scenario where Node-RED is used to enable an Allen Bradley PLC, which uses ethernet/IP, to communicate with a Siemens PLC, which uses S7, using a no-code solution. This example is geared toward beginners and assumes that the end-user knows how to use PLCs, but may be using FlowFuse or Node-RED for the first time.&lt;/p&gt;
&lt;h2 id=&quot;premise&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#premise&quot;&gt;Premise&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;FlowFuse Mock production facility&quot; alt=&quot;Mock production facility&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The figure above shows the layout of a mock production facility. Inside this facility, operations suggested adding stack lights as an extra visual aid for operators to get a quick status of its 4 conveyor lines, avoiding the need to constantly monitor the HMI/SCADA displays.&lt;br /&gt;
Engineering has suggested adding a siemens S7 1200 PLC with an IO link connection to 4 stacklights, with each line PLC sending basic status information to the stacklight PLC to control the stack light outputs.&lt;br /&gt;
Line 1-3 PLCs are Siemens-based, and can communicate with the stacklight PLC natively over S7. But line 4 is an Allen Bradley PLC that uses ethernet/IP, and can&#39;t communicate with the stacklight PLC without some form of protocol conversion.&lt;br /&gt;
Traditionally, we&#39;d use protocol gateway hardware, like Anybus or Red Lion, to convert ethernet/IP to S7.&lt;br /&gt;
But for this application, we will instead use FlowFuse, a pure software-based approach, to convert ethernet/IP to S7. Let&#39;s walk through the process.&lt;/p&gt;
&lt;h2 id=&quot;pre-requisites-and-set-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#pre-requisites-and-set-up&quot;&gt;Pre-Requisites and Set Up&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#flowfuse&quot;&gt;FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to our two PLCs, we’ll be using FlowFuse software to serve our Node-RED instance. You can either self-host, on-premise or in the cloud. Or use the managed service &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this example, we will be using a self-hosted FlowFuse instance running on &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;data-treatment-on-ethernet%2Fip-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#data-treatment-on-ethernet%2Fip-plc&quot;&gt;Data Treatment on Ethernet/IP PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our Allen Bradley line 4 PLC, we will send some arbitrary tags of various datatypes to the stacklight PLC for illustrative purposes, described in table 1 below -&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Tag&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Data Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Conveyor_RTS&lt;/td&gt;
&lt;td&gt;BOOL&lt;/td&gt;
&lt;td&gt;Conveyor Ready to Start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Robot_RTS&lt;/td&gt;
&lt;td&gt;BOOL&lt;/td&gt;
&lt;td&gt;Robot is Ready to Start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Robot_Position&lt;/td&gt;
&lt;td&gt;REAL&lt;/td&gt;
&lt;td&gt;Robot Arm position (degrees)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conveyor_Running&lt;/td&gt;
&lt;td&gt;BOOL&lt;/td&gt;
&lt;td&gt;Conveyor is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Line4_State&lt;/td&gt;
&lt;td&gt;DINT&lt;/td&gt;
&lt;td&gt;Line 4 Machine State&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Line4_Fault&lt;/td&gt;
&lt;td&gt;BOOL&lt;/td&gt;
&lt;td&gt;Line 4 is faulted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Table 1 - Line 4 Tags to be sent to Stacklight PLC&lt;/p&gt;
&lt;p&gt;We can send any atomic data type we want, but it must be globally (controller) scoped.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the AB Controller Tags&quot; alt=&quot;&amp;quot;Screenshot showing the AB Controller Tags&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Each tag must also have external read/write access enabled.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the AB Tag Properties&quot; alt=&quot;&amp;quot;Screenshot showing the AB Tag Properties&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-treatment-on-s7-plc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#data-treatment-on-s7-plc&quot;&gt;Data Treatment on S7 PLC&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the Siemens PLC, we have a DB for the data from the Line 4 PLC to be written to.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the DBs attributes, “optimized block access” must be disabled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The tags must be writeable and accessible&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Siemens Tag DB Properties&quot; alt=&quot;&amp;quot;Screenshot showing the Siemens Tag DB Properties&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-4.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;“No protection” must be set in the CPU properties&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Siemens CPU Properties&quot; alt=&quot;&amp;quot;Screenshot showing the Siemens CPU Properties&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;create-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#create-the-flow&quot;&gt;Create The Flow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With both PLCs up and running and properly set up to send/receive remote data, we can now create a flow to act as our protocol converter.&lt;/p&gt;
&lt;h3 id=&quot;install-custom-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#install-custom-nodes&quot;&gt;Install Custom Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we need to add two custom nodes that will give Node-RED the ability to read/write ethernet/IP and S7 data.&lt;/p&gt;
&lt;p&gt;Click the hamburger icon → manage pallette&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Screenshot showing the &#39;Manage palette option&#39; in the menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-6.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;On the &lt;code&gt;install&lt;/code&gt; tab, search for &lt;code&gt;s7&lt;/code&gt; and install the &lt;code&gt;node-red-contrib-s7&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Installing S7 node&quot; alt=&quot;&amp;quot;Installing S7 node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-7.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Next, search for &lt;code&gt;ethernet&lt;/code&gt; and install the &lt;code&gt;node-red-contrib-cip-ethernet-ip&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;InstallING EthernetIP Node&quot; alt=&quot;&amp;quot;InstallING EthernetIP Node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-8.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;
Go to the &lt;code&gt;nodes&lt;/code&gt; tab and confirm both custom nodes have been properly installed.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of &#39;Nodes&#39; tab showing Installed nodes List&quot; alt=&quot;&amp;quot;Screenshot of &#39;Nodes&#39; tab showing Installed nodes List&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-9.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;set-up-ethernet%2Fip-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#set-up-ethernet%2Fip-data&quot;&gt;Set Up Ethernet/IP Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s start by dragging a &lt;code&gt;eth-ip in&lt;/code&gt; node onto the pallette. Then add a new endpoint, which will point to our Line4 PLC.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing dragged &#39;eth-ip in&#39; node and it&#39;s config tab&quot; alt=&quot;&amp;quot;Screenshot showing dragged &#39;eth-ip in&#39; node and it&#39;s config tab&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-10.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In the endpoint &lt;code&gt;connection&lt;/code&gt; properties, the connection information must match the PLC, so set the IP address and CPU slot number appropriately. Also, the default cycle time is 500ms. Depending on your application, polling the CPU at 500ms may be appropriate. But being that this is a simple stacklight, 500ms is unnecessarily fast. So we will change it to 1000ms, which is a more appropriate polling rate for this type of application.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the eth-ip Endpoint config&quot; alt=&quot;&amp;quot;Screenshot showing the eth-ip Endpoint config&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-11.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;On the &lt;code&gt;Tags&lt;/code&gt; tab, populate the tag information to match our Allen Bradley PLC. Then select &lt;code&gt;Update&lt;/code&gt; to complete configuration of the &lt;code&gt;eth-ip endpoint&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing eth-ip Endpoint Tags&quot; alt=&quot;&amp;quot;Screenshot showing eth-ip Endpoint Tags&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-12.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now that we have our endpoint, let’s finish configuring the &lt;code&gt;eth-ip in&lt;/code&gt; node.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;select the endpoint we just created&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;select the first tag in the drop-down&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;give the node a descriptive name&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screeshot showing the eth-ip in Node config&quot; alt=&quot;Screeshot showing the eth-ip in Node config&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-13.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now let’s set up a quick test to confirm our PLC connection is valid by adding a &lt;code&gt;debug&lt;/code&gt; node to the &lt;code&gt;eth-ip in&lt;/code&gt; node. Then hit &lt;code&gt;deploy&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;note - you can see we also have a &lt;code&gt;comment&lt;/code&gt; above the nodes that describes what is happening. This is optional but good practice to help organize and understand your flow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output of the debug console did not report any errors so communication appears to be okay.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the output of eth-ip in Debug panel&quot; alt=&quot;Screenshot showing the output of eth-ip in Debug panel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-14.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;But just to confirm, let’s toggle the value and see if comes through.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the eth-ip node output in Debug panel after Toggle&quot; alt=&quot;Screenshot showing the eth-ip node output in Debug panel after Toggle&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-15.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;So by toggling the value and see the result, here we confirmed 2 things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We can detect changes in value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;code&gt;eth-ip in&lt;/code&gt; node only sends a message when the value changes, also known as Report by Exception.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the &lt;code&gt;eth-ip in&lt;/code&gt; node implicitly uses report by exception, and the protocol doesn&#39;t rely on contiguous data consistency (unlike modbus, for instance), we can receive our data one tag at a time to keep our flow simple.&lt;/p&gt;
&lt;p&gt;Now we can remove the debug node and add the additional &lt;code&gt;eth-ip in&lt;/code&gt; nodes to receive the remaining tags from our Line 4 PLC.&lt;/p&gt;
&lt;p&gt;Here’s how the the flow should look at this point.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of Line 4 PLC Nodes&quot; alt=&quot;Screenshot of Line 4 PLC Nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-16.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;set-up-s7-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#set-up-s7-data&quot;&gt;Set Up S7 Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we’ll set up the S7 endpoint, using an &lt;code&gt;s7 out&lt;/code&gt; node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of s7 out Node on Palette&quot; alt=&quot;Screenshot of s7 out Node on Palette&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-17.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Populate the connection properties to match your hardware. The cycle time is updated to 1000ms to match the cycle time of our &lt;code&gt;eth-ip in&lt;/code&gt; nodes. You can adjust this value to match your intended application.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the S7 endpoint Connection&quot; alt=&quot;&amp;quot;Screenshot showing the S7 endpoint Connection&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-18.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;On the &lt;code&gt;Variables&lt;/code&gt; tab, some special formatting is required to point to the absolute reference of the tag DB location in the S7 PLC.&lt;/p&gt;
&lt;p&gt;For information on how to format S7 absolute tag references in a way the &lt;code&gt;s7 endpoint&lt;/code&gt; node is expecting, refer to the &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-s7&quot;&gt;node documentation&lt;/a&gt; for further information.&lt;/p&gt;
&lt;p&gt;For reference, here is an example of how we set the tags in our stacklight PLC example and how it looks in our &lt;code&gt;s7 endpoint&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of s7 endpoint Variables&quot; alt=&quot;&amp;quot;Screenshot of s7 endpoint Variables&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-19.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Once the tags are populated we can select our configured endpoint from the dropdown list, point to our first variable, &lt;code&gt;Conveyor_RTS&lt;/code&gt;, and give the node a name.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of S7 out Config&quot; alt=&quot;&amp;quot;Screenshot of S7 out Config&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-20.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Repeat this process for the remaining tags.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of Stacklight PLC Nodes&quot; alt=&quot;&amp;quot;Screenshot of Stacklight PLC Nodes&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-21.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;test-the-conversion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#test-the-conversion&quot;&gt;Test the Conversion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The only thing remaining is to simply wire the nodes together, and confirm the values pass through.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of the complete flow with live Data&quot; alt=&quot;&amp;quot;Screenshot of the complete flow with live Data&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-22.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Manipulate the incoming values and confirm the data passes through as expected. Because of the report by exception nature of the &lt;code&gt;eth-ip in&lt;/code&gt; node, tag changes should be near instantaneous on the receiving PLC.&lt;/p&gt;
&lt;p&gt;We can stop here, but we can improve this flow by adding a &lt;code&gt;filter&lt;/code&gt; node on our REAL data-type, &lt;code&gt;Robot_Position&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;add-filter-to-real-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#add-filter-to-real-data&quot;&gt;Add Filter to REAL data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Depending on how noisy the REAL data is, which is common with unfiltered 4-20mA field transmitters, and how much granularity you need to capture, it is good practice to add a filter on REAL data to reduce FieldBus traffic coming out of our soft protocol converter.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the Filter node Configuration&quot; alt=&quot;&amp;quot;Screenshot showing the Filter node Configuration&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-23.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In the example above, we arbitrarily applied a 3% &lt;a href=&quot;https://flowfuse.com/node-red/core-nodes/filter/&quot;&gt;deadband&lt;/a&gt;
to the &lt;code&gt;Robot_Position&lt;/code&gt; value, which means that the value must change by greater than or equal to 3% compared to the last input value, or else the data will be discarded before being sent to the stacklight PLC.&lt;/p&gt;
&lt;p&gt;You can adjust the deadband to find the right balance for your particular application.&lt;/p&gt;
&lt;p&gt;We can see the effect the deadband filter had by adding debug nodes before and after the filter.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Filter Node Debug&quot; alt=&quot;Filter Node Debug&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/e-to-p-24.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;As shown above, when &lt;code&gt;Robot_Position&lt;/code&gt; changed from 15.6 to 15.6999..., the value was captured on the input of the filter, but was discarded on the output.&lt;/p&gt;
&lt;p&gt;When the &lt;code&gt;Robot_Position&lt;/code&gt; went from 15.6999 to 18, the filter allowed it to pass as it exceeded the deadband limit we had set.&lt;/p&gt;
&lt;p&gt;Use filters to optimize your fieldbus converter network performance, especially if dealing with noisy signals or large quantities of REAL datatypes.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/node-red-as-a-no-code-ethernet_ip-to-s7-protocol-converter/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this tutorial, we demonstrated how to use Node-RED as a free Ethernet/IP to S7 protocol converter using a simple no-code approach.  We showed how to configure PLC tags to be sent remotely using Ethernet/IP, how to configure PLC tags to be received remotely using S7, and how to create the flow to use Node-RED to seamlessly convert incoming PLC data between the two protocols using &lt;code&gt;node-red-contrib-cip-ethernet-ip&lt;/code&gt; and &lt;code&gt;node-red-contrib-s7&lt;/code&gt; custom nodes.  We also took things one step further and added a &lt;code&gt;filter&lt;/code&gt; node to optimize FieldBus network traffic by putting a deadband on REAL data being sent to the receiving PLC.&lt;/p&gt;
&lt;p&gt;The end result is a simple to set up, free and performant industrial protocol converter that requires minimal PLC configuration, which allows this application to be applied in non-mission critical production systems with minimal, if any downtime.  Additionally, the protocol traffic can be visually observed in real-time for easy trouble-shooting and fault analysis by simply accessing the Node-RED UI.&lt;/p&gt;
&lt;p&gt;In later tutorials, we can show ways this simple flow can be extended to add additional capabilities not normally available in traditional off-the-shelf protocol gateways. If you found this tutorial helpful, or have any questions or comments, please leave us a comment and let us know your thoughts.&lt;/p&gt;
&lt;p&gt;JSON source code for the flow used in this tutorial is provided below -&lt;/p&gt;
&lt;div id=&quot;nr-flow-165&quot; style=&quot;height: 500px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow165 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Line 4 to Stacklight PLC&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c97a4c9bd1981757&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;AB EIP/CIP - Line 4 PLC&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2cc5227ef6a90814&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Conveyor_RTS&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Conveyor_RTS&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fe18ef80f9e18c13&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;9308dcbda17274c7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;comment&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Siemens S7 - Stacklight PLC&#92;&quot;,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fe18ef80f9e18c13&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Conveyor_RTS&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Conveyor_RTS&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:200,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;94fe6b73efa1c56b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Robot_RTS&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Robot_RTS&#92;&quot;,&#92;&quot;x&#92;&quot;:180,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7774d6ce188c288c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7e9564cd59e3d0a2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Robot_Position&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Robot_Position&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;832807bfdc4b76f0&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c0f712b9e355f1f8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Conveyor_Running&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Conveyor_Running&#92;&quot;,&#92;&quot;x&#92;&quot;:210,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;fbf1b3e38897a9c7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;db77621e418f1222&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Line4_State&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Line4_State&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;cdeffd9e52cc4384&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;848af9b76f969dd2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;mode&#92;&quot;:&#92;&quot;single&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Line4_Fault&#92;&quot;,&#92;&quot;program&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Read Line4_Fault&#92;&quot;,&#92;&quot;x&#92;&quot;:190,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;0c595b0ac2550593&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7774d6ce188c288c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Robot_RTS&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Robot_RTS&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f1572463c50bb4cb&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Robot_Position&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Robot_Position&#92;&quot;,&#92;&quot;x&#92;&quot;:620,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fbf1b3e38897a9c7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Conveyor_Running&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Conveyor_Running&#92;&quot;,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cdeffd9e52cc4384&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Line4_State&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Line4_State&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;0c595b0ac2550593&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 out&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;endpoint&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;variable&#92;&quot;:&#92;&quot;Line4_Fault&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Write Line4_Fault&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;832807bfdc4b76f0&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;rbe&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;ad7b17411c8e83aa&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;func&#92;&quot;:&#92;&quot;deadbandEq&#92;&quot;,&#92;&quot;gap&#92;&quot;:&#92;&quot;3%&#92;&quot;,&#92;&quot;start&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;inout&#92;&quot;:&#92;&quot;in&#92;&quot;,&#92;&quot;septopics&#92;&quot;:true,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;topi&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:360,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f1572463c50bb4cb&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4ab2910b66e16220&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;eth-ip endpoint&#92;&quot;,&#92;&quot;address&#92;&quot;:&#92;&quot;192.168.0.5&#92;&quot;,&#92;&quot;slot&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;cycletime&#92;&quot;:&#92;&quot;1000&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Line4&#92;&quot;,&#92;&quot;vartable&#92;&quot;:{&#92;&quot;&#92;&quot;:{&#92;&quot;Conveyor_RTS&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;BOOL&#92;&quot;},&#92;&quot;Robot_RTS&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;BOOL&#92;&quot;},&#92;&quot;Robot_Position&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;REAL&#92;&quot;},&#92;&quot;Conveyor_Running&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;BOOL&#92;&quot;},&#92;&quot;Line4_State&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;DINT&#92;&quot;},&#92;&quot;Line4_Fault&#92;&quot;:{&#92;&quot;type&#92;&quot;:&#92;&quot;BOOL&#92;&quot;}}}},{&#92;&quot;id&#92;&quot;:&#92;&quot;a1bec25858c6f3ef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;s7 endpoint&#92;&quot;,&#92;&quot;transport&#92;&quot;:&#92;&quot;iso-on-tcp&#92;&quot;,&#92;&quot;address&#92;&quot;:&#92;&quot;192.168.0.10&#92;&quot;,&#92;&quot;port&#92;&quot;:&#92;&quot;102&#92;&quot;,&#92;&quot;rack&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;slot&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;localtsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;localtsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;remotetsaphi&#92;&quot;:&#92;&quot;01&#92;&quot;,&#92;&quot;remotetsaplo&#92;&quot;:&#92;&quot;00&#92;&quot;,&#92;&quot;connmode&#92;&quot;:&#92;&quot;rack-slot&#92;&quot;,&#92;&quot;adapter&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;busaddr&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;cycletime&#92;&quot;:&#92;&quot;1000&#92;&quot;,&#92;&quot;timeout&#92;&quot;:&#92;&quot;3000&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Stacklight PLC&#92;&quot;,&#92;&quot;vartable&#92;&quot;:[{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X0.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Conveyor_RTS&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X0.1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Robot_RTS&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,R2&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Robot_Position&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X6.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Conveyor_Running&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,DI8&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Line4_State&#92;&quot;},{&#92;&quot;addr&#92;&quot;:&#92;&quot;DB1,X12.0&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Line4_Fault&#92;&quot;}]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow165.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-165&#39;) })&lt;/script&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/introducing-the-flowforge-community-forum/</id>
        <title>Introducing the FlowFuse Community Forum</title>
        <summary>A Community Forum for support, inspiration, and knowledge sharing</summary>
        <updated>2023-06-12T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/introducing-the-flowforge-community-forum/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;We are thrilled to announce the launch of the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;Community Forum for FlowFuse&lt;/a&gt;.
A forum dedicated to empowering developers and enthusiasts to create innovative
applications using FlowFuse, Node-RED and related technologies.&lt;/p&gt;
&lt;p&gt;Our community faces a new set of challenges, for example how to configure FlowFuse templates as administrator, or integration of the FlowFuse platform into another existing environment. These questions do not fit on the Node-RED discourse which is why FlowFuse now sports our own Community Forum. Furthermore, it’s the intent to keep the Node-RED forums vendor agnostic by the OpenJS foundation. Given FlowFuse is a vendor, it’s a fine balance to find. We hope and intend to be additive to the Node-RED community at large.&lt;/p&gt;
&lt;p&gt;At FlowFuse, our vision is to create a thriving community of Node-RED and MQTT enthusiasts who are passionate about building real-world solutions. We believe in the power of collaboration, knowledge sharing, and problem-solving. With this in mind, FlowFuse aims to foster a positive and inclusive environment where members can engage in discussions, exchange ideas, and support one another.&lt;/p&gt;
&lt;p&gt;Initially the forum is used to allow for discussions under each blog post on the FlowFuse blog, as well as a venue to provide community support. We also welcome discussions on the roadmap and backlog of FlowFuse. We have hopes that this community thrives and provides guidance, inspiration and opportunity to learn.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/community-news-06/</id>
        <title>Community News June 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-06-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/community-news-06/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for June 2023, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;new-release&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#new-release&quot;&gt;New Release&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This week we released FlowFuse 1.8, featuring high availability for Node-RED and DevOps software delivery pipelines. Both these features were in high demand from our community and will make it easier to reliably deliver Node-RED for business critical applications.&lt;/p&gt;
&lt;p&gt;Read about the details of FlowFuse 1.8 in our &lt;a href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/&quot;&gt;release announcement&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;building-node-red-applications-for-scalability-and-high-availability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#building-node-red-applications-for-scalability-and-high-availability&quot;&gt;Building Node-RED Applications for Scalability and High Availability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our June webinar will focus on the new FlowFuse 1.8 feature of running high availability Node-RED applications. Marian Demme, FlowFuse Product Manager, will lead this session and share practical insights and best practices to show how FlowFuse can unlock the true potential of Node-RED in large-scale deployments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/webinars/2023/building-scalable-ha-node-red/&quot;&gt;Sign-up today&lt;/a&gt; to join us on June 22.&lt;/p&gt;
&lt;h3 id=&quot;build-an-edge-to-cloud-solution-with-the-ming-stack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#build-an-edge-to-cloud-solution-with-the-ming-stack&quot;&gt;Build an Edge-to-Cloud Solution with the MING Stack&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On June 27, FlowFuse is doing a webinar with our friends at InfluxDB. A great opportunity to see how easy it is to use Node-RED and InfluxDB to send data from the edge to the cloud.  &lt;a href=&quot;https://www.influxdata.com/resources/build-an-edge-to-cloud-solution-with-the-ming-stack/?utm_source=partner&amp;amp;utm_medium=referral&amp;amp;utm_campaign=2023-06-27_Webinar_FlowFuse-NodeRED&amp;amp;utm_term=speaker&quot;&gt;Sign-up today&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/&quot;&gt;Bringing High Availability to Node-RED&lt;/a&gt; - FlowFuse CTO discusses the strategy for delivering high availability in the FlowFuse platform.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Two articles featuring how to connect Modbus data with Node-RED:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/node-red/protocol/modbus/&quot;&gt;Using Node-RED to Visualize Industrial Production Data via Modbus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[Best Practices Integrating a Modbus Device With Node-RED](/blog/2023/05/integrating modbus with node-red/)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/&quot;&gt;Node-RED Tips - Dashboard Edition&lt;/a&gt; - A new set of Node-RED quick tips that are focused on using Node-RED Dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/&quot;&gt;Persisting chart data in Node-RED Dashboards&lt;/a&gt; - How to store data from the Node-RED Dasbhaord chart node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/05/node-red-community-survey-results/&quot;&gt;Node-RED Community Survey Results&lt;/a&gt; - A quick summary of the Node-RED Community Survey results.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/&quot;&gt;FlowFuse 1.7 Now Available with Remote Node-RED Editor Access&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gerrit Riessen has published a list of &lt;a href=&quot;https://gorenje.medium.com/fourteen-for-fourteen-against-why-i-love-hate-and-connect-with-node-23797f9466ec&quot;&gt;Pros and Cons for using Node-RED&lt;/a&gt;. It is a pretty comprehensive list so check it out. FlowFuse is working to address some of the cons in Gerrit&#39;s list, specifically software delivery pipelines and the ability to deploy out to many end points.&lt;/p&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/community-news-06/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4796271004&quot;&gt;DevOps Engineer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4843566004&quot;&gt;Sales Representative&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/flowforge-1-8-released/</id>
        <title>FlowFuse now offers High Availability Node-RED</title>
        <summary>FlowFuse 1.8 makes Node-RED applications more reliable and scalable, plus more streamline deployment pipelines.</summary>
        <updated>2023-06-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/flowforge-1-8-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 1.8 introduces two key features that allow organizations to reliably deploy Node-RED applications into production. In 1.8, it is now possible to run Node-RED applications with high availability so the application is more scalable and more fault tolerant. FlowFuse 1.8 also introduces software deliver pipelines, so development teams can now set up dev/test/production environments for their Node-RED applications.&lt;/p&gt;
&lt;h2 id=&quot;more-reliable-and-scalable-node-red-applications&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#more-reliable-and-scalable-node-red-applications&quot;&gt;More reliable and scalable Node-RED applications&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse now makes it possible to deploy business critical applications built in Node-RED that are reliable and scalable. The new 1.8 features allows a Node-RED instance to be deployed in high availability mode, meaning two instances of the same Node-RED flows are available behind a load balancer. This allows for increased traffic to be automatically distributed across the two Node-RED instances. This means your Node-RED applications can handle more traffic and experience less downtime. For more details, please see our &lt;a href=&quot;https://flowfuse.com/docs/user/high-availability/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, we&#39;re pleased to offer a 30-day premium trial license for self-managed installs on Kubernetes. To avail of this offer, book a demo at &lt;a href=&quot;https://flowfuse.com/book-demo/&quot;&gt;flowforge.com/book-demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;High Availability is our first &lt;a href=&quot;https://flowfuse.com/handbook/engineering/product/versioning/#preview-features&quot;&gt;preview feature&lt;/a&gt;, and your feedback is crucial. We encourage you to try out HA in your Node-RED instances and share your experiences with us. Your feedback will help us refine this feature and make it even better.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;mbDkjKhVwIw&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;devops-pipelines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#devops-pipelines&quot;&gt;DevOps Pipelines&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse 1.8 introduces the concept of Pipelines to better organize your Node-RED development. Development team can now set up different staging environments for different steps in the development cycle, ex. test, development and production. Node-RED instances can be pushed along a pipeline as they move along the development process. This allows for a better organized and predictable development process for your team.&lt;/p&gt;
&lt;p&gt;The new Pipelines feature builds upon the Staged Development support that we introduced in&lt;a href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/&quot;&gt;FlowFuse Version 1.4&lt;/a&gt;. We highly recommend that development teams avoid developing their flows directly in production instances. This approach fosters a more reliable and robust development process, reducing the risks associated with production environment modifications. Instead, start your development in a dedicated development or test instance and then deploy your Node-RED instance to production once they have been thoroughly tested and reviewed.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;Pbql22f3vqY&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;user-interface-for-device-agent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#user-interface-for-device-agent&quot;&gt;User interface for Device Agent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In our previous release, we introduced &lt;a href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/&quot;&gt;Editor Access for Devices&lt;/a&gt;. Now, the FlowFuse Device Agent now comes with its very own User Interface (UI) for configuration.&lt;/p&gt;
&lt;p&gt;Imagine this: Your industrial equipment arrives with the Device Agent preinstalled. In the past, you might have faced challenges in configuring and connecting your device with FlowFuse, particularly if you had no direct shell access. But not any more.&lt;/p&gt;
&lt;p&gt;With the newly introduced UI, you can easily set up and connect your device with FlowFuse without needing to access the command line interface directly. This simplifies the process significantly and saves you time. For more details, see our &lt;a href=&quot;https://flowfuse.com/docs/device-agent/introduction/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;node-red-3.1-beta-3-available&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#node-red-3.1-beta-3-available&quot;&gt;Node-RED 3.1 Beta 3 Available&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Cloud is a great place to try out the new Node-RED features, with FlowFuse Cloud now including the &lt;a href=&quot;https://discourse.nodered.org/t/node-red-3-1-0-beta-3-released/78716&quot;&gt;Node-RED 3.1.0-beta.3&lt;/a&gt;. If you want to try this version you can &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/&quot;&gt;duplicate your instance&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/docs/user/changestack/&quot;&gt;upgrade your stack&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ongoing-topics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#ongoing-topics&quot;&gt;Ongoing Topics&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;soc2-certification&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#soc2-certification&quot;&gt;SOC2 Certification&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re making great strides on our journey towards SOC2 certification, striving to meet the highest industry standards for security and privacy. While we&#39;re not quite ready to disclose specific milestones, be assured that everything is progressing smoothly. As we continue working diligently towards our target, we promise to keep you informed every step of the way. Our unwavering commitment to deliver secure and private services to our customers and partners remains our foremost priority. Stay tuned for more updates!&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;Product Roadmap Page&lt;/a&gt; to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When editing a device in developer mode via the tunnel/proxy connection, a list of team projects are not presented in the &amp;quot;Target&amp;quot; field of the project-link nodes. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2228&quot;&gt;#2228&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If a user invites an external user to their team with an sso-enable email domain, when that user registers and logs in, they are not added to the team they were invited to and must be re-invited. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2232&quot;&gt;#2232&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No warning given if tying to start device editor when NR is not running &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2233&quot;&gt;#2233&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Stuck on the form Create a new Application &amp;amp; Instance after using an already known instance name &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2221&quot;&gt;#2221&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the device agent finds itself in Developer mode, it stops pulling snapshots from the platform &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/97&quot;&gt;#97&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Accessing the Admin Settings General page resets the Platform Statstics token &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2140&quot;&gt;#2140&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Selection of Team and Instance in nr-tools-plugin not possible &lt;a href=&quot;https://github.com/FlowFuse/nr-tools-plugin/issues/15&quot;&gt;#15&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;HOME env var not set within Node-RED process &lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-launcher/issues/117&quot;&gt;#117&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.8.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/flowforge-1-8-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there. Additionally you can go the the &lt;a href=&quot;https://discourse.nodered.org/c/vendors/flowfuse/24&quot;&gt;community forum&lt;/a&gt; if you have
any feedback or feature requests.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/import-modules/</id>
        <title>Use any npm module in Node-RED</title>
        <summary>See how you can easily import any npm module, for use in a Node-RED function node.</summary>
        <updated>2023-06-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/import-modules/"/>
        <author><name></name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Node-RED has &lt;a href=&quot;https://flows.nodered.org/search?type=node&quot; target=&quot;_blank&quot;&gt;an incredibly rich resource of integrations available&lt;/a&gt;, but sometimes you need that little bit of extra functionality, or access to a Node.js module that doesn&#39;t have it&#39;s own custom nodes in Node-RED. &lt;strong&gt;We can easily import any npm module within the built-in Node-RED function nodes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Historically in Node-RED, you would have needed to manually &lt;code&gt;npm install&lt;/code&gt; modules from the command line, but now that it&#39;s so easy to run Node-RED in the Cloud, where you don&#39;t have easy access to those tools, what are the other options available?&lt;/p&gt;
&lt;h2 id=&quot;function-node---setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/import-modules/#function-node---setup&quot;&gt;Function Node - Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Location of the &#39;add&#39; button in order to import an npm module intoa  function node&quot; alt=&quot;Location of the &amp;quot;add&amp;quot; button in order to import an npm module intoa  function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/npmimport-add.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;All you need is the name of the module you want to import, then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Drop in a new &amp;quot;function&amp;quot; node &amp;amp; double-click it&lt;/li&gt;
&lt;li&gt;Switch to the &amp;quot;Setup&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Underneath the &amp;quot;modules&amp;quot; tab, click &amp;quot;+ add&amp;quot; in the bottom-left of the window.&lt;/li&gt;
&lt;li&gt;Enter the name of the module you want to use in the newly created row, and (optionally) modify the &lt;code&gt;variable&lt;/code&gt; that this module will be imported in as.&lt;/li&gt;
&lt;li&gt;Switch back to the &amp;quot;On Message&amp;quot; tab and write your function. Your new module will be available via the &lt;code&gt;variable&lt;/code&gt; you defined in the &amp;quot;Setup&amp;quot; tab.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;example%3A-moment.js&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/import-modules/#example%3A-moment.js&quot;&gt;Example: Moment.js&lt;/a&gt;&lt;/h2&gt;
&lt;video width=&quot;560&quot; height=&quot;315&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/MomentJS+Demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;
&lt;p&gt;Recently we wanted to use &lt;a href=&quot;https://www.npmjs.com/package/moment&quot;&gt;moment&lt;/a&gt; for some custom date calculations. Whilst there was set of &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-moment&quot;&gt;Moment Node-RED nodes&lt;/a&gt; already available, it didn&#39;t have all of the functionality we needed.&lt;/p&gt;
&lt;p&gt;So, all we needed to do was import the module into a function node, and define our comparison there instead, here&#39;s a working example:&lt;/p&gt;
&lt;h2 id=&quot;example%3A-easy-crc&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/import-modules/#example%3A-easy-crc&quot;&gt;Example: Easy CRC&lt;/a&gt;&lt;/h2&gt;
&lt;video width=&quot;560&quot; height=&quot;315&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/Easy+CRC+Demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;
&lt;p&gt;Something we see &lt;a href=&quot;https://discourse.nodered.org/search?q=crc%20order%3Alatest&quot;&gt;a lot on the Node-RED Forums&lt;/a&gt; are questions on how to conduct CRC calculations. There is a popular node module &lt;code&gt;easy-crc&lt;/code&gt; that can be imported and used in the function nodes, e.g:&lt;/p&gt;
&lt;h2 id=&quot;example%3A-posthog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/import-modules/#example%3A-posthog&quot;&gt;Example: PostHog&lt;/a&gt;&lt;/h2&gt;
&lt;video width=&quot;560&quot; height=&quot;315&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;https://website-data.s3.eu-west-1.amazonaws.com/PostHog+Node+Demo.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;
&lt;p&gt;Node-RED is great for &lt;a href=&quot;https://flowfuse.com/solutions/data-integration/&quot;&gt;data integration&lt;/a&gt;. We use &lt;a href=&quot;https://posthog.com/&quot; target=&quot;_blank&quot;&gt;PostHog&lt;/a&gt; for our internal Product Analysis. We record live events as they occur on FlowFuse Cloud to better understand features that are (and are not) used.&lt;/p&gt;
&lt;p&gt;We wanted to investigate whether or not we could add backdated data, which in theory was possible via their &lt;a href=&quot;https://posthog.com/docs/libraries/node&quot; target=&quot;_blank&quot;&gt;posthog-node&lt;/a&gt; module. We wanted to populate it with data driven from our own database and API.&lt;/p&gt;
&lt;p&gt;Within two minutes, we could wire up a node to retrieve data from our API, and then ingest it into &lt;code&gt;posthog-node&lt;/code&gt; via the import of a function node.&lt;/p&gt;
&lt;h2 id=&quot;simplify-function-node-creation-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/import-modules/#simplify-function-node-creation-with-flowfuse&quot;&gt;Simplify Function Node Creation with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; provides a powerful platform to enhance, scale, and secure your Node-RED applications efficiently. One of our latest features, the &lt;strong&gt;FlowFuse Assistant&lt;/strong&gt;, is designed to streamline the process of creating Function nodes.&lt;/p&gt;
&lt;p&gt;With the FlowFuse Assistant, you can leverage AI to generate Function nodes effortlessly. Just input your prompt, and the Assistant will handle the creation for you, saving time and reducing manual coding.&lt;/p&gt;
&lt;p&gt;To explore how to make the most of the FlowFuse Assistant and its capabilities, check out the &lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;Assistants Documentation&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/</id>
        <title>Bringing High Availability to Node-RED</title>
        <summary>How we are tackling the hard problems of HA in FlowFuse</summary>
        <updated>2023-06-02T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Many companies look to deploy Node-RED into use cases that require the application
to have a high degree of availability, reliability, and scalability. Following up
our &lt;a href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/&quot;&gt;previous post on the subject&lt;/a&gt;, in this
post I’m going to look at some of the technical details of achieving HA, the
approaches available and what that means for the work we’re doing at FlowFuse
and upstream in Node-RED.&lt;/p&gt;
&lt;p&gt;Everyone we speak to has a different set of requirements for this topic. To help
with the discussion, I’m going to look at two ways of approaching it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;hot-spare approach&lt;/strong&gt; where you have a second instance of the application
ready to take over when the primary fails. This achieves availability but
doesn’t contribute to scalability.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;load-balanced approach&lt;/strong&gt; where you have a second active instance of the
application and work is shared between them. If either fails, the other
continues running. A side-effect of this approach is a higher potential
through-put and scalability; although in practice you need to ensure capacity
to tolerate an instance failing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To consider which approach is most appropriate in the context of Node-RED, we
need to look at the benefits and complications of each approach. It comes down
to two factors; statefulness and how work is routed.&lt;/p&gt;
&lt;h3 id=&quot;statefulness&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/#statefulness&quot;&gt;Statefulness&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are two types of state to consider when thinking about a Node-RED flow:
&lt;strong&gt;explicit&lt;/strong&gt; and &lt;strong&gt;implicit&lt;/strong&gt; state.&lt;/p&gt;
&lt;p&gt;Explicit state is what is programmed into the flow. For example, a flow may store
state in Context or use an external database service. Within FlowFuse we provide
two types of context - the default in-memory context store and a database-backed
persistent store. Currently the database-backed store includes a memory-caching
layer to provide better performance and interoperability. That gets tricky when
you want to have multiple instances sharing the same store. The context API
doesn’t provide a way to atomically update values - so you can get into classic
concurrency issues around two applications trying to update the same value.&lt;/p&gt;
&lt;p&gt;The other type of state is that which is implicitly maintained in a flow - even
if the user hasn’t explicitly configured it. For example, the Smooth node can be
used to calculate a running average value of messages passing through it. The
node does that by keeping in memory the recent values so it can recalculate the
average with each update. If you have multiple instances, then the node will be
calculating the average for just the message its instances sees.&lt;/p&gt;
&lt;p&gt;Another example of implicit state is the Batch node that can be used to group
messages into batches. Again - it will only be able to do that for the selection
of messages the instance receives.&lt;/p&gt;
&lt;p&gt;It very much depends on the requirements of a flow and what nodes it uses, as to
how the state can be handled.&lt;/p&gt;
&lt;p&gt;In the hot-spare approach, as only one instance is active at any time, a lot of
the explicit state handling will work as expected. However the implicit state
remains bound to the individual Node-RED instances.&lt;/p&gt;
&lt;p&gt;In the load-balanced approach, care has to be taken to ensure any state generated
by the flow is done in a way that copes with multiple instances accessing it at
the same time.&lt;/p&gt;
&lt;p&gt;A key take-away from this being that a flow has to be created with HA and/or scaling
in mind.&lt;/p&gt;
&lt;h3 id=&quot;routing-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/#routing-work&quot;&gt;Routing work&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED makes it easy to integrate with lots of different sources of events.
A couple of the most common being HTTP and MQTT. When considering how to handle
multiple instances of an application we need to think about how work is routed
to those instances.&lt;/p&gt;
&lt;p&gt;HTTP is the most well understood; you put a load-balancing proxy in front of the
Node-RED instances and it takes care of sharing out the incoming requests. In
the hot-spare scenario, the proxy needs to know which instance is active - that
requires some coordination within the platform to track that properly.&lt;/p&gt;
&lt;p&gt;MQTT is commonly used with Node-RED, but unlike HTTP which is in-bound, MQTT
works by having Node-RED create an out-bound connection to a broker and then
subscribing to the topics of interest. In the early days of MQTT that would mean
each instance would subscribe to the same set of topics and receive every message.
That doesn’t really fit any HA model.&lt;/p&gt;
&lt;p&gt;With the publication of MQTTv5, the concept of Shared Subscriptions was added;
the ability for a group of clients to connect, subscribe to the same topic and
have the broker distribute messages between them. At this point you do get load
balancing across your Node-RED instances - as long as the MQTT nodes are suitably
configured.&lt;/p&gt;
&lt;p&gt;There are lots of other nodes that can be used to trigger flows, whether by
listening for events on an API, connecting to locally attached hardware and many
things in between. Typically, those that are more cloud-aligned, such as messaging
systems like Kafka and AMQP will have very well established ways of doing load
balancing.&lt;/p&gt;
&lt;p&gt;Managing out-bound connections gets more complicated in the hot-spare scenario.&lt;/p&gt;
&lt;p&gt;If we only had to deal with in-bound connections, the hot-spare instance can just
sit there waiting for work to be passed its way. But once you have out-bound
connections, then you have a problem. The hot-spare instance should only create
its out-bound connections when it becomes the active instance. In real terms,
that means the Node-RED flows should only be started when the instance becomes
active.&lt;/p&gt;
&lt;p&gt;With our goal to minimize the Mean Time To Recovery (MTTR), we need to find a
way to get that spare instance running as quickly as possible; if it takes just
as long to start the spare instance as it does to restart the failed primary
instance, then it isn’t much of an improvement.&lt;/p&gt;
&lt;p&gt;The key here is that Node-RED allows you to start the runtime without the flows
running. That gets everything loaded and the runtime ready ahead of time. It can
then start the flows at a moment&#39;s notice with a simple call to the runtime admin
API.&lt;/p&gt;
&lt;h3 id=&quot;detecting-failure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/#detecting-failure&quot;&gt;Detecting failure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A key requirement of the hot-spare approach to HA is knowing when to failover to
the spare.&lt;/p&gt;
&lt;p&gt;This requires close monitoring of the active instance to know whether it&#39;s still
working. How quickly you can detect failure is key to reducing the time to recovery.
This is where you have to think about the different ways an instance could fail -
has it crashed, has it hung, has it got ‘stuck’?&lt;/p&gt;
&lt;p&gt;Detecting failure usually involves some combination of heartbeat ‘pings’ between
the instances to check each is able to respond to requests. The spare instance
then needs to be able to decide for itself whether it should become the active
instance - and do so safely. You do not want to accidentally have two instances
active at the same time. This can get quite complicated to achieve safely, but
there are a number of approaches that can be used. We’ll be exploring them as we
continue our journey towards HA.&lt;/p&gt;
&lt;h3 id=&quot;editing-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/#editing-flows&quot;&gt;Editing Flows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Within the Node-RED architecture, each instance also serves up its own editor.
This is what you get when you point your web browser at it.&lt;/p&gt;
&lt;p&gt;In a HA world, once you have multiple instances running behind an HTTP load
balancer, there is a tricky question of how you edit the flows. If each request
hits a different instance, just loading the editor will result in different bits
coming from different instances. That can typically be solved at the load balancer
level by creating sticky-sessions; ensuring for a given client, each request is
routed to a consistent instance. That solves part of the issue, but the next
challenge is what to do when the Deploy button is pressed. That is how new flows
are passed from the editor to the runtime. When you have multiple instances, we
need to make sure that they all get updated. That is quite a tricky problem to
solve with the current Node-RED APIs - and something we’ll be working on both in
FlowFuse and in the upstream Node-RED project to resolve.&lt;/p&gt;
&lt;p&gt;That said, a more immediate solution could well be to take advantage of separate
development/production instances. You develop in a single instance and, when happy
with what you’ve got, roll it out to your HA-ready production instance. This
bypasses the need to edit the flows in the HA environment at all.&lt;/p&gt;
&lt;p&gt;Whichever method is used, there is a question of how you minimize downtime whilst
deploying an update. In a purely in-bound environment, solutions can be built
where the new application is deployed alongside the old version and, when everything
is ready, the in-bound events are redirected to the new version. But that isn’t
feasible when you have out-bound connections to deal with as well. For some users,
having a scheduled maintenance window for doing updates will be completely acceptable.&lt;/p&gt;
&lt;p&gt;As with the hot-spare approach to failover, a similar method could be used that
starts new instances of Node-RED alongside the old, but with the flows all stopped.
Then, once everything is ready, the old instances are stopped and the new instances
started - minimizing the downtime, although not completely removing it.&lt;/p&gt;
&lt;h3 id=&quot;continuing-the-ha-journey-at-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/bringing-high-availability-to-node-red/#continuing-the-ha-journey-at-flowfuse&quot;&gt;Continuing the HA journey at FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So the question is how are we going to apply all of this to what we’re building
at FlowFuse. We cannot do everything at once, so we have to prioritize which
scenarios we’re going to address first. Consequently, drawing from customer
feedback, we have chosen to start with the scaling side of high availability -
allowing multiple copies of an instance to be run with appropriate load
balancing put in front of it.&lt;/p&gt;
&lt;p&gt;We are building FlowFuse as an open platform with the ability to run on top of
Docker Compose and Kubernetes. As we get into some of these HA features, we will
need to look carefully at where we can lean on these underlying technologies -
we don’t want to reinvent the wheel here.&lt;/p&gt;
&lt;p&gt;Our initial focus is going to be when running in a Kubernetes environment - just
as we do with our hosted FlowFuse Cloud platform. Kubernetes provides lots of
the building blocks for creating a scalable and highly available solution, but
it certainly doesn’t do all of the work for you.&lt;/p&gt;
&lt;p&gt;We&#39;ve identified our initial set of tasks and changes to how we&#39;ll run Node-RED
instance with the k8s environment. You can follow our progress with this
&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2156&quot;&gt;issue&lt;/a&gt; on our backlog.&lt;/p&gt;
&lt;p&gt;I hope this post has given some useful insight into the problems we’re looking
to solve at FlowFuse. As it&#39;s such an important requirement for many users we’ll
keep you updated as we make progress.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/</id>
        <title>Node-RED Tips - Dashboard Edition</title>
        <summary>Save yourself time when working with Node-RED Dashboards with these three tips.</summary>
        <updated>2023-06-01T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;p&gt;In this Node-RED Tips article, we are going to focus on &lt;a href=&quot;https://flows.nodered.org/node/node-red-dashboard&quot;&gt;Node-RED Dashboard&lt;/a&gt;. Dashboard is a great tool for creating HMI (Human Machine Interfaces), it&#39;s also the most popular custom node for Node-RED with thousands of downloads per week.&lt;/p&gt;
&lt;h3 id=&quot;1.-responsive-layouts-(almost)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/#1.-responsive-layouts-(almost)&quot;&gt;1. Responsive layouts (almost)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Responsive design is the ability for a webpage to change its content to best fit the features of a device used to view the page. For example, when viewing a graph on a mobile phone or a laptop the available screen space differs significantly in size as well as aspect-ratio.&lt;/p&gt;
&lt;p&gt;Dashboard doesn&#39;t offer the feature to change graph sizes based on the screen of a viewing device. That being said, there is one trick you can use to make your dashboards a lot more useful on small and large screens alike.&lt;/p&gt;
&lt;p&gt;Place your content into Dashboard &#39;groups&#39;, those groups can make use of wider screens by sitting side by side where the screen is big enough while stacking vertically on smaller devices.&lt;/p&gt;
&lt;p&gt;The image below shows what happens when you change the screen size for this dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Changing the aspect ratio of the screen&quot; alt=&quot;Changing the aspect ratio of the screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/responsive.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;d like to try this out on your own Node-RED, you can import the flow below.&lt;/p&gt;
&lt;div id=&quot;nr-flow-162&quot; style=&quot;height: 500px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow162 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;tab&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Flow 1&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;info&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;env&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d388b48fcbed93a1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ba1ff527abfa5261&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gage&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#00b500&#92;&quot;,&#92;&quot;#e6e600&#92;&quot;,&#92;&quot;#ca3838&#92;&quot;],&#92;&quot;seg1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;seg2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;diff&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;80780894450cfb6d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ba1ff527abfa5261&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;label&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:80,&#92;&quot;y&#92;&quot;:80,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49e78ff51c3a1ea3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;07b44990e5d5b5f6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;ba1ff527abfa5261&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1482bcf69325aa92&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:120,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;49e78ff51c3a1ea3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;49e78ff51c3a1ea3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;low&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;high&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;inte&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d388b48fcbed93a1&#92;&quot;,&#92;&quot;07b44990e5d5b5f6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;38996d8eb9f6535d&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f6052a3dccc77ea3&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gage&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#00b500&#92;&quot;,&#92;&quot;#e6e600&#92;&quot;,&#92;&quot;#ca3838&#92;&quot;],&#92;&quot;seg1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;seg2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;diff&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cf5599fbda28e614&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f6052a3dccc77ea3&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;label&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:80,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f093c63e17a620ba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;936438ebf9eef986&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;f6052a3dccc77ea3&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;60a40faa335f943e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:280,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;f093c63e17a620ba&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;f093c63e17a620ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;low&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;high&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;inte&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;38996d8eb9f6535d&#92;&quot;,&#92;&quot;936438ebf9eef986&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e284b90164e648e6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;1e4a72d62ed7564c&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gage&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#00b500&#92;&quot;,&#92;&quot;#e6e600&#92;&quot;,&#92;&quot;#ca3838&#92;&quot;],&#92;&quot;seg1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;seg2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;diff&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;cabe7a8150dbfaf6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;1e4a72d62ed7564c&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;label&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:80,&#92;&quot;y&#92;&quot;:380,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b9862186954c4b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ac116116c56e6c3c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;1e4a72d62ed7564c&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bb27ef41380ec1d2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:420,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7b9862186954c4b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7b9862186954c4b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;low&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;high&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;inte&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e284b90164e648e6&#92;&quot;,&#92;&quot;ac116116c56e6c3c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e891f555bad51f01&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_gauge&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;fcc4481a9e329266&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;gtype&#92;&quot;:&#92;&quot;gage&#92;&quot;,&#92;&quot;title&#92;&quot;:&#92;&quot;gauge&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;units&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#00b500&#92;&quot;,&#92;&quot;#e6e600&#92;&quot;,&#92;&quot;#ca3838&#92;&quot;],&#92;&quot;seg1&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;seg2&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;diff&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa090cd1a0e97885&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_button&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;fcc4481a9e329266&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:false,&#92;&quot;label&#92;&quot;:&#92;&quot;Update&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;color&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;bgcolor&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;x&#92;&quot;:80,&#92;&quot;y&#92;&quot;:500,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bb4e945a2a8e681c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c3a8aa84dfc85fe&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;fcc4481a9e329266&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;60&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;796f79538c15dd66&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:90,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;bb4e945a2a8e681c&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bb4e945a2a8e681c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;random&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;e351b1251dfbc2f7&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;low&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;high&#92;&quot;:&#92;&quot;100&#92;&quot;,&#92;&quot;inte&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;x&#92;&quot;:220,&#92;&quot;y&#92;&quot;:520,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e891f555bad51f01&#92;&quot;,&#92;&quot;1c3a8aa84dfc85fe&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba1ff527abfa5261&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine 1&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;39383a7a648193dd&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;f6052a3dccc77ea3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine 2&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;39383a7a648193dd&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;1e4a72d62ed7564c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine 3&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;39383a7a648193dd&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;fcc4481a9e329266&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Machine 4&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;39383a7a648193dd&#92;&quot;,&#92;&quot;order&#92;&quot;:4,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;39383a7a648193dd&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Node-RED Tips&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow162.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-162&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;2.-add-more-than-one-series-of-data-to-a-line-chart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/#2.-add-more-than-one-series-of-data-to-a-line-chart&quot;&gt;2. Add more than one series of data to a line chart&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Being able to add more than one series of data to a single chart can make the data far more useful. One great way to use this is to compare the same data from different sensors. In this example I&#39;m going to show the external and internal temperature at a location on the same chart.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Graphing two series on the same line chart&quot; alt=&quot;Graphing two series on the same line chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/temp-graph.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To do this you need to give a different msg.topic to each series, you can add that using a change node before passing the data to the chart.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to view this chart on your own Node-RED, you can import the flow below.&lt;/p&gt;
&lt;div id=&quot;nr-flow-163&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow163 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;3eb08d4843164efc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58569b35dacd54f3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;41e847ff22249c0e&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;width&#92;&quot;:&#92;&quot;12&#92;&quot;,&#92;&quot;height&#92;&quot;:&#92;&quot;5&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;Celsius&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;dd HH:mm&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;604800&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:280,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;c4a13220356f76d3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;58569b35dacd54f3&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[{&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;:[&#92;&#92;&#92;&quot;inside&#92;&#92;&#92;&quot;,&#92;&#92;&#92;&quot;outside&#92;&#92;&#92;&quot;],&#92;&#92;&#92;&quot;data&#92;&#92;&#92;&quot;:[[{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685015544647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685015844687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016144791,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016444933,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016745032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017045123,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017345223,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017645339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017945424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018245500,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018545670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018860580,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019160814,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019460832,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019760943,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020061037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020361249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020661264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020961381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021261473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021561721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021876580,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022176696,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022476852,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022776957,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023077032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023377120,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023677234,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023977339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024277455,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024577576,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024892578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025192616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025492757,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025792847,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026092949,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026393052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026693174,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026993234,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027293387,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027593514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027908550,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028208624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028508708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028808828,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029108909,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029409026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029709096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030009262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030309361,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030609541,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030924565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031239588,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031539702,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031839784,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032139922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032440027,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032740134,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033040252,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033340317,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033640450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033940507,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034240592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034540633,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034840784,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035140888,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035441026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035741107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036041205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036341328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036641457,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036941583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037256578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037556715,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037856773,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038156902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038457023,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038757090,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039057219,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039357278,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039657449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039957553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040257570,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040557615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040857735,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041157843,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041457971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041758072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042058154,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042358273,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042658392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042958486,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043258518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043558568,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043858688,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044158769,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044458908,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044758984,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045059095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045359169,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045659320,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045959367,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046259469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046559497,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046859589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047159647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047459714,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047759793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048059921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048359994,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048659997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048960056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049260070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049560116,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049860167,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050160212,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050460281,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050760368,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051060400,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051360435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051660553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051960585,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052260665,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052560675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052860700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053160749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053460790,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053760855,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054060931,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054361019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054661030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054961121,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055261227,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055576250,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055891289,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056191290,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056491397,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056791444,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057091489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057391516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057691607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057991660,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058291741,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058606760,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058906775,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059206866,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059506900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059806979,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060107035,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060407099,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060707132,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061007199,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061307220,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061607228,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061907286,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062207289,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062507315,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062807355,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063107395,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063407413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063707465,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064007492,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064307565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064607587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064907609,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065207618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065507642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065807670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066107679,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066407758,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066707760,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067007798,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067307865,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067622903,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067937922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068237945,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068537971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068838009,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069138060,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069453065,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069753104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070053108,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070353140,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070653170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070953219,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071253232,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071553258,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071853260,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072153324,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072453329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072753343,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073053359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073353402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073653411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073953453,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074253462,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074553509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074853529,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075153554,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075453556,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075753590,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076053642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076368644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076668676,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076968685,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077268752,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077583729,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077883800,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078198760,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078498762,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078798782,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079098837,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079398903,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079698965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079999013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080299091,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080599234,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080899276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081199340,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081499403,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081799441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082099467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082399584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082699624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082999670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083299724,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083599810,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083899884,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084199935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084500001,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084800063,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085115072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085415170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085715226,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086015289,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086315365,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086615447,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086915501,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087215603,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087515642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087815732,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088115759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088415793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088715840,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089015891,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089315950,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089616045,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089916094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090216153,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090516202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090816299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091116304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091416326,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091716409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092016500,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092316555,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092616597,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092916687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093216749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093516770,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093816833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094116862,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094416941,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094717014,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095017079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095317146,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095617198,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095917267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096217380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096517436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096817481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097117519,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097417582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097717607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098017734,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098317791,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098617850,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098917939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099218020,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099518088,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099818190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100118269,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100418304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100718355,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101018437,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101318544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101618646,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101918720,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102218803,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102518914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102818997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103119093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103419119,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103719183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104019263,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104319361,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104619467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104919565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105219692,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105261657,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105275726,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105316848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105388676,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105475001,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105501466,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105576628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105627162,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105653330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105684112,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105722222,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105769629,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105825666,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105889137,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105910507,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105970749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106270828,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106570844,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106870845,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107170872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107485846,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107785884,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108100859,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108400859,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108700881,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109000885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109300898,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109615915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109930873,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110230928,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110545931,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110845948,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111145989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111460988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111761062,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112061067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112361107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112661141,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112961145,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113261191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113561195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113861234,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114161272,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114461288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114761326,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115061359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115361389,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115661413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115961522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116276440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116576471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116876500,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117176511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117476538,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117776599,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118091580,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118391620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118691646,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118991656,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119291661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119591684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119891711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120191732,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120491763,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120791797,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121091832,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121406802,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121706853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122021885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122336872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122636878,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122936903,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123236933,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123536988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123837007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124137007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124437098,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124737193,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125037270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125337370,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125637493,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125937530,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126237627,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126537712,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126837733,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127137746,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127437870,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127737940,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128038026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128338109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128638215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128938321,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129238409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129538484,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129838514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130138614,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130438644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130738716,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131038856,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131338912,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131639028,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131939140,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132239222,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132539344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132839390,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133154381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133454402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133754494,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134054557,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134354644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134654753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134954810,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135254894,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135554961,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135854990,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136155013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136455070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136755172,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137055242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137355339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137655440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137955504,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138255592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138555675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138855742,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139155750,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139455841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139755904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140055961,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140356100,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140656187,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140956268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141256384,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141556467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141856547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142156630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142456678,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142756713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143056833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143356922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143657019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143957116,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144257203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144557262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144857393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145157511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145457515,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145757583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146057687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146357780,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146657878,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146957969,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147258066,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147558163,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147858255,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148158303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148458377,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148758392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149058441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149358550,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149658652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149958735,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150258816,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150558892,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150858996,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151159109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151459166,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151759230,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152059291,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152359350,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152659430,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152959526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153259622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153559728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153859883,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154159899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154459974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154760016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155060096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155360142,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155660284,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155960372,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156260469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156560559,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156860664,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157160732,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157460827,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157760925,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158061041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158361093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158661174,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158961238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159261356,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159561460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159861591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160161622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160461727,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160761798,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161061899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161361960,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161662030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161962083,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162262205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162562329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162862420,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163162514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163462630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163762689,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164062785,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164362862,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164662929,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164962989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165263080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165563213,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165863284,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166163398,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166463432,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166763562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167063657,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167363752,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167663818,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167963868,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168263959,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168564052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168864152,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169164297,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169464371,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169764428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170064553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170364630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170664689,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170964744,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171264839,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171564944,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171865046,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172165136,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172465216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172765270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173065378,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173365491,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173665574,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173965634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174265651,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174565770,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174865842,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175165962,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175466056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175766151,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176066247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176366347,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176666421,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176966481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177266535,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177566618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177866715,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178166786,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178466868,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178766964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179067013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179367161,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179667226,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179967298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180267304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180567400,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180867474,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181167605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181467661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181767781,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182067847,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182367916,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182668010,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182968067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183268142,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183568218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183868264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184168356,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184468449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184768557,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185068624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185368711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185668784,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185968847,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186268953,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186568982,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186868996,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187169094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187469146,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187769224,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188069250,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188369327,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188669411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188969475,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189269500,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189569548,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189869583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190169645,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190469717,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190769801,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191069848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191369885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191669980,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191970014,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192270055,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192570106,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192870150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193170235,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193470249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193770302,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194070311,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194370328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194670393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194985377,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195285440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195585471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195885473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196185514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196485562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196800615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197115572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197415601,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197715640,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198015652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198315706,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198615725,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198915775,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199215786,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199515831,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199815856,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200115858,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200415875,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200715913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201015918,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201315964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201616032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201916044,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202231051,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202531062,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202831089,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203131095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203431195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203746138,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204046168,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204346182,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204646203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204946241,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205246243,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205546262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205846296,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206146312,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206446335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206746375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207046395,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207346549,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207661544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207961647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208261700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208561766,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208861855,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209161943,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209462007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209762097,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210077101,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210377152,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210677231,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210977296,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211277406,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211577537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211877620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212177660,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212477797,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212777837,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213077881,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213377932,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213677997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213978205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214293200,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214593270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214893375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215193482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215493529,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215793531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216093643,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216393738,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216693784,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216993880,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217293962,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217594100,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217894151,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218194256,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218494376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218794467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219094477,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219394675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219709688,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220009789,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220309889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220609986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220910080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221210236,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221510267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221810331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222110381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222410481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222710598,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223010661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223310759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223610881,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223911009,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224211106,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224511191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224811272,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225111309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225411398,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225711438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226011552,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226311659,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226611773,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226911876,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227211995,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227512070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227812175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228112250,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228412314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228712352,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229012470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229312587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229612662,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229912736,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230212847,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230512904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230813034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231113081,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231413122,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231713183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232013342,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232328321,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232628419,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232928528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233228604,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233528687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233828743,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234128809,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234428883,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234728963,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235028977,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235329064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235629163,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235929251,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236229341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236529423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236829513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237129612,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237429697,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237729771,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238029832,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238329902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238629974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238930096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239230144,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239530225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239830331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240130366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240430509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240730597,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241030697,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241330716,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241630792,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241930839,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242230957,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242531061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242831116,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243131245,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243431358,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243731422,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244031484,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244331554,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244631614,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244931700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245231790,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245531908,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245832059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246132107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246432206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246732334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247032445,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247332472,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247632538,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247932668,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248232731,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248532806,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248832930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249133015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249433093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249733189,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250033291,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250333378,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250633446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250933493,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251233569,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251533627,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251833774,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252133852,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252433955,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252734091,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253034179,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253334257,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253634325,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253934367,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254234489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254534587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254834680,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255134805,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255434885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255735002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256035085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256335179,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256635254,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256935309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257235338,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257535440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257835520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258135635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258435709,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258735790,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259035904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259335965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259636005,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259936052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260236148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260536249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260836320,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261136489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261436489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261736607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262036710,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262336806,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262636943,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262936991,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263237019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263537113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263837223,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264137303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264437449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264737520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265037596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265337653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265637725,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265937773,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266237884,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266537917,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266837940,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267138006,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267438089,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267738177,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268038239,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268338288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268638340,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268938413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269238479,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269538567,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269838641,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270138681,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270438761,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270738813,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271038911,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271338993,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271638994,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271939107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272239155,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272539230,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272839299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273139339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273439382,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273739450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274039516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274339570,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274639651,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274939715,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275239718,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275539821,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275839883,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276139936,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276439971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276740019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277040061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277340154,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277640177,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277940231,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278240249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278540299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278840376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279140399,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279440422,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279740489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280040542,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280340547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280640612,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280940692,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280995978,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281186232,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281372604,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281687601,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281710226,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281749591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281762017,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281799605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282023556,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282044430,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282166915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282208131,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282217923,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282260379,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282339652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282364558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282412077,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282588188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282614967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282852605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282960718,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685282980565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283037810,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283067001,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283122144,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283272482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283343031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283445211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283473050,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283503945,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283559122,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283661335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283679196,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283753141,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283789923,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685283796674,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284111596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284411624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284726634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285041633,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285341650,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285641691,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285941711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286241759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286541841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286856821,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287156833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287456865,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287756902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288056933,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288357007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288671988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288972004,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289272052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289572077,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289872089,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290172161,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290487147,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290787163,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291087218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291387247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291687274,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291987283,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292287334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292587380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292887389,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293187427,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293502456,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293817480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294117492,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294417507,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294717548,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295017585,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295317622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295617633,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295917642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296217701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296532704,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296832750,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297132754,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297432771,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297732796,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298032828,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298332882,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298647889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298947921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299247969,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299547997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299848026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300163050,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300463065,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300763075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301063109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301363164,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301678208,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301993216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302293269,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302593314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302908310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303208329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303508359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303808369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304108395,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304408424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304708455,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305008461,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305308490,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305608530,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305908539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306208562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306508616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306823616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307123649,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307423661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307723699,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308023733,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308323779,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308638772,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308938793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309238818,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309538833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309838872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310138910,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310453907,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310768906,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311068915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311368965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311668966,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311968998,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312269016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312569034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312869061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313169072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313484093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313784097,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314084113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314384134,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314684165,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314984191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315299157,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315599168,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315899192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316199221,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316514243,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316814264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317129218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317444217,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317744298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318059259,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318359275,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318659355,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318959404,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319259419,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319559443,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319859535,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320159597,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320459678,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320759851,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321074857,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321374890,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321674930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321974980,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322274993,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322575024,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322875122,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323175196,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323475244,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323775309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324075375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324375402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324675425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324975485,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325275523,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325575582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325875647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326175713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326475768,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326775825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327075908,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327376002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327676015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327976059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328276184,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328591156,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328891332,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329206306,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329506397,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329806440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330106549,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330406587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330706687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331006741,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331306759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331606822,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331906872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332206974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332507043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332807216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333122210,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333422298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333722396,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334022464,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334322536,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334622591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334922644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335222714,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335522841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335822919,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336122954,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336423087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336723138,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337023185,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337323274,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337623330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337923414,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338223520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338523616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338823724,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339123797,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339423870,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339723950,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340024030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340324090,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340624115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340924164,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341224265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341524353,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341824453,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342124531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342424622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342724753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343024799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343324830,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343624890,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343924971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344225070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344525149,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344825216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345125344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345425362,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345725441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346025536,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346325591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346625679,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346925731,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347225748,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347525839,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347825931,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348126031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348426089,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348726163,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349026225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349326308,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349626392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349926466,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350226553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350526651,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350826811,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351141763,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351441827,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351741927,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352042064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352342100,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352642170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352942245,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353242314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353542387,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353842461,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354142491,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354442557,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354742628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355042729,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355342838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355642921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355942977,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356243149,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356558148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356858211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357158249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357458282,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357758424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358058471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358358569,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358658635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358958716,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359258767,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359558873,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359858954,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360159014,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360459077,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360759117,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361059194,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361359285,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361659377,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361959454,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362259508,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362559586,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362859674,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363159756,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363459810,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363759869,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364059953,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364360040,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364660157,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364960261,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365260272,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365560367,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365860483,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366160569,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366460633,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366760670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367060781,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367360928,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367660996,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367961125,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368261267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368561326,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368861443,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369161528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369461571,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369761618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370061811,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370361876,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370661975,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370962096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371262161,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371562287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371862386,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372162471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372462563,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372762583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373062692,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373362813,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373662925,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373963012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374263073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374563193,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374863306,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375163412,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375463446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375763533,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376063611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376363690,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376663795,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376963909,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377263998,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377564112,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377864184,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378164260,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378464309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378764426,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379064528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379364568,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379664627,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379964711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380264778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380564838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380864899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381164922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381464995,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381765085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382065145,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382365238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382665304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382965394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383265458,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383565523,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383865573,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384165635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384465670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384765740,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385065812,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385365909,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385665940,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385966015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386266095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386566159,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386866204,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387166270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387466325,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387766371,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388066417,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388366441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388666495,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388966561,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389266600,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389566607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389866660,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390166677,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390466746,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390781720,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391081770,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391381808,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391681836,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391981922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392281964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392582032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392897029,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393197037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393497068,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393797107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394097146,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394397195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394697240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394997269,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395297315,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395597344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395897378,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396197391,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396497411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396797418,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397097514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397397526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397697553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397997603,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398297622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398597700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398897737,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399212765,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399527768,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399827776,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400127841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400442841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400742935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401057950,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401357960,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401657984,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401957995,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402258067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402573081,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402873096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403173117,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403473129,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403773148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404073175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404373229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404688249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404988317,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405288409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405588488,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405888522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406188569,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406488623,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406788688,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407088721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407388765,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407688838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407988885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408288915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408588993,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408889074,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409189147,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409489206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409789249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410089310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410389345,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410704354,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411004452,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411304516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411604552,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411904625,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412204887,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412519762,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412819867,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413119886,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413419976,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413719986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414020028,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414320085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414620140,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414920229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415220270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415520407,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415820425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416120509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416420519,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416720605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417020626,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417320672,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417620774,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417920843,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418220900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418520971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418821022,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419121073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419421171,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419721181,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420021225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420321304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420621355,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420921447,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421221522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421521582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421821663,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422121736,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422421818,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422721865,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423021869,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423321956,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423622015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423922080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424222162,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424522203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424822288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425122362,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425422438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425722513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426022547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426322620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426622723,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426922744,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427222854,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427522913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427823002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428123104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428423173,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428723329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429038338,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429338390,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429638534,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429938550,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430238655,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430538750,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430838822,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431139008,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431439050,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431739109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432039156,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432339204,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432639299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432939394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433239499,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433539575,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433839700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434139771,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434439873,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434739965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435040038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435340054,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435640133,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435940205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436240311,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436540423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436840548,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437140665,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437440701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437740799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438040887,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438340964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438641030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438941063,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439241150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439541265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439841366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440141451,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440441506,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440741607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441041684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441341786,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441641830,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441941863,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442241939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442542010,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442842108,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443142199,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443442319,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443742376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444042480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444342574,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444642649,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444942748,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445242792,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445542799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445842907,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446143003,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446443122,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446743194,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447043298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447343341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447643442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447943557,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448243632,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448543708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448843747,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449143768,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449443878,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449743965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450044053,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450344178,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450644263,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450944279,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451244382,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451544448,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451844600,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452144626,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452444701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452744749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453044818,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453344909,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453645071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453945113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454245205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454545276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454845390,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455145455,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455445552,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455745631,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456045706,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456345813,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456645826,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456945928,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457246034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457546104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457846188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458146263,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458446341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458746470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459046554,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459346643,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459646708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459946734,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460246833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460546913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460847002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461147079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461447115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461747181,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462047303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462347360,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462647457,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462947533,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685463247622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685463437946,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685463752894,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464067891,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464367932,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464668016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464968034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465268109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465568127,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465868179,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466168200,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466468292,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466783247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467083281,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467383324,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467683356,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467983393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468283508,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468598507,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468898532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469198568,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469498602,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469798635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470098653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470398701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470698741,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470998770,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471298800,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471598821,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471898877,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472198886,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472498957,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472798992,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473099049,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473414059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473714086,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474014164,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474314238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474629191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474929212,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475229261,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475529275,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475829340,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476129417,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476429433,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476729449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477029470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477329512,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477629544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477929562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478229615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478529641,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478829667,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479129749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479429791,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479729807,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480029843,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480329850,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480629899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480929954,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481244998,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481545012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481845043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482145093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482445120,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482745153,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483045222,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483345235,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483645258,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483945299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484245340,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484545382,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484845385,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485145425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485445459,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485745479,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486045546,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486345575,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486645633,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486945725,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487260693,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487560707,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487860814,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488175808,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488475825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488775853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489075914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489375930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489675982,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489976039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490276048,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490576126,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490876150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491176154,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491476262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491791218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492091237,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492391276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492691341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492991352,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493291416,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493591464,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493891476,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494191553,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494491555,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494806655,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495121636,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495436647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495736703,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496036726,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496336779,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496636854,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496951873,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497251911,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497566911,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497866915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498166972,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498466989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498767043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499067095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499367129,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499667180,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499967184,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500282215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500582236,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500882309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501197336,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501497371,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501797405,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502097446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502397471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502697518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502997526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503297549,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503597589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503897624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504197687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504497728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504797753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505097809,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505397837,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505697885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505997899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506297916,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506597958,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506897987,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507198004,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507498078,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507798110,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508098131,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508398152,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508698194,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508998213,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509298220,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509598290,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509898323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510198331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510498370,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510798393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511098454,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511398491,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511698520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512013528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512313605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512628564,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512928630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513228650,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513528663,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513828703,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514143711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514443729,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514743749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515043937,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515358896,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515658956,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515959007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516259087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516559112,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516859194,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517174175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517474229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517774323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518074366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518374438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518674561,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518974586,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519274602,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519574700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519889719,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520189753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520489831,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520789861,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521089913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521390016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521690069,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521990135,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522290216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522590301,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522905260,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523205311,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523505402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523805456,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524105543,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524405592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524705754,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525005757,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525305830,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525605894,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525905934,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526205944,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526505986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526806078,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527106180,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527406287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527706314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528006417,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528306469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528606541,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528906576,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529206598,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529506705,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529806799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530106900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530406997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530707031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531007135,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531307217,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531607277,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531907312,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532207333,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532507449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532807538,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533107607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533407716,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533707801,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534007891,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534307936,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534607976,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534908043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535208090,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535508186,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535808331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536108352,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536408438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536708630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537023666,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537323705,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537623753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537923799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538223965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538538965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538839060,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539139180,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539439233,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539739375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540039424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540339520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540639601,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540939668,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541239749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541539840,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541839913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542139995,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542440177,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542740192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543040283,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543340389,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543640471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543940473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544240621,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544540685,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544840799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545140901,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545441001,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545741065,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546041186,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546341243,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546641292,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546941376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547241438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547541565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547841634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548141711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548441854,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548741902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549042002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549342099,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549642156,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549942238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550242287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550542321,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550842435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551142532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551442679,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551742742,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552042824,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552342904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552643024,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552943102,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553243197,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553543262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553843353,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554143366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554443531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554743589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555043690,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555343799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555643872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555943930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556244056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556544148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556844209,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557144344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557444363,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557744405,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558044539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558344605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558644713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558944785,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559244901,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559544945,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559845042,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560145143,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560445241,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560745257,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561045328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561345445,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561645525,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561945646,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562245696,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562545795,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562845871,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563145971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563446094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563746173,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564046283,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564346314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564646386,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564946460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565246561,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565546656,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565846745,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566146812,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566446933,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566746982,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567047084,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567347176,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567647243,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567947275,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568247414,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568547487,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568847582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569147698,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569447750,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569747835,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570047948,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570348041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570648135,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570948186,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571248285,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571548397,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571848461,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572148552,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572448646,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572748724,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573048812,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573348924,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573648998,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573949035,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574249162,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574564170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574864211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575164295,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575464392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575764473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576064520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576364561,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576664649,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576964764,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577264783,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577564825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577864898,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578165022,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578465041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578765123,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579065190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579365242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579665270,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579965342,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580265419,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580565474,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580865528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581165617,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581465707,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581765780,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582065871,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582365914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582665994,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582966029,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583266054,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583566137,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583866167,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584166249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584466332,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584766387,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585066444,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585366558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585666591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585966705,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586281700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586581763,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586881831,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587181935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587481999,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587782043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588082116,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588382188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588682255,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588982296,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589282341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589582405,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589882472,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590182540,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590482618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590782722,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591082771,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591382819,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591682931,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591982967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592282986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592583082,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592883165,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593183195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593483277,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593783380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594083450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594383491,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594683592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594983618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595283711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595583730,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595883817,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596183896,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596483953,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596784061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597084124,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597384139,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597684213,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597984240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598284312,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598584338,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598884381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599184436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599499407,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599799490,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600099528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600399539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600699637,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600999644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601299689,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601599758,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601899826,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602199848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602499869,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602799939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603099979,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603414978,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603715053,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604030039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604330117,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604630167,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604930199,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605230238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605530260,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605830318,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606130319,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606430335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606730393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607030458,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607330485,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607630516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607930568,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608230576,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608530643,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608830684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609130723,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609430778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609745753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610045798,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610345834,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610645876,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610945921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611245935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611545963,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611845989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612146117,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612446189,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612746312,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613046346,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613346425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613646580,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613961556,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614261648,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614576669,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614876695,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615176733,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615476808,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615776863,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616076917,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616376987,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616677033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616977113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617277203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617577236,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617877275,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618177324,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618477408,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618777447,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619077601,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619377646,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619677730,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619977761,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685620017473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685620080667,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.1}],[{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685015251039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685015551015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685015851010,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016151028,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016451042,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685016751019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017051028,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017351047,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017651031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685017951098,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018251018,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018551020,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685018851032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019151038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019451035,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685019751031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020051038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020351040,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020651063,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685020951079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021251036,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021551137,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685021851047,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022151057,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022451042,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685022751080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023051043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023351058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023651118,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685023951188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024251055,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024551051,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685024851052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025151135,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025451076,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685025751061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026051071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026351158,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026651115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685026951071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027251066,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027551148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685027851058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028151059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028451112,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685028751146,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029051091,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029351104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029651134,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685029951350,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030251085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030551087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685030851113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031151160,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031451109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685031751080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032051082,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032351518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032651206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685032951081,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033251086,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033551096,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685033851075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034151086,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034451139,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685034751066,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035051075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035351084,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035651091,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685035951102,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036251109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036551080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685036851085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037151113,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037451085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685037751124,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038051100,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038351547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038651116,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685038951187,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039251190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039551190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685039851181,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040151138,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040451132,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685040751183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041051160,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041351171,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041651173,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685041951215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042251220,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042551262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685042851204,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043151252,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043451209,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685043751246,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044051210,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044351522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044651215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685044951218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045251281,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045551345,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685045851232,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046151240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046451276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685046751262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047051266,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047351285,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047651267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685047951728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048251321,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048551265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685048851352,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049151302,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049451264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685049751268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050051322,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050351309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050651266,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685050951264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051251276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051551291,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685051851384,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052151274,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052451281,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685052751280,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053051279,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053351326,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053651310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685053951323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054251377,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054551303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685054851307,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055151655,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055451302,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685055751335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056051330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056351435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056651370,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685056951348,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057251335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057551642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685057851342,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058151360,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058451395,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685058751511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059051391,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059351339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059651359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685059951438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060251356,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060551372,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685060851371,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061151374,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061451412,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685061751394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062051381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062352047,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062651444,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685062951373,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063251410,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063551479,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685063851380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064151391,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064451471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685064751589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065051396,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065351399,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065651409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685065952272,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066251396,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066551403,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685066851417,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067151442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067451399,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685067751460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068051420,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068351485,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068651412,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685068951402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069251450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069551482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685069851414,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070151414,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070451408,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685070752331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071051424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071351428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071651498,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685071951451,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072251483,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072551428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685072851477,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073151490,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073451401,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685073751433,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074051433,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074351659,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074651481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685074951442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075251486,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075553145,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685075851454,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076151559,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076451455,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685076751637,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077051562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077351466,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077651495,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685077951596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078251465,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078551490,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685078851486,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079152413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079451481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685079751484,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080051515,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080353153,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080651466,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685080951559,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081251496,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081552662,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685081851505,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082151498,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082451574,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685082752768,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083051516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083351518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083651522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685083951825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084251526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084551531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685084851537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085154315,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085451540,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685085751599,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086051532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086352440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086651538,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685086951544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087251583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087552469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685087851550,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088151549,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088451547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685088752994,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089051545,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089351589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089651598,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685089952825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090251561,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090551636,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685090851564,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091152016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091451594,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685091751567,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092051581,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092352469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092651613,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685092951598,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093251572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093551684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685093851596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094151578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094451581,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685094753849,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095051634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095351592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095651582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685095952262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096251665,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096551653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685096851597,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097151894,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097451605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685097751603,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098051603,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098351825,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098651611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685098951612,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099251620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099554557,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685099851611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100151610,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100451674,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685100751631,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101051671,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101351650,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101651625,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685101952592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102251628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102551620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685102851630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103152663,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103451625,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685103751638,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104051653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104351690,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104651625,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685104951669,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685105251635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106270209,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106570210,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685106870262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107170259,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107470202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685107770205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108070201,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108370268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108670211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685108970215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109270264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109570225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685109870210,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110170276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110470215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685110770218,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111070267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111370237,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111670242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685111970278,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112270243,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112570286,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685112870312,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113170279,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113470259,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685113770274,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114070330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114370346,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114670290,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685114970303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115270293,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115570345,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685115870301,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116170341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116470425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685116770319,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117070306,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117370344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117670330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685117970336,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118270330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118570325,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685118870362,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119170359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119470369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685119770365,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120070363,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120370385,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120670359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685120970383,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121270373,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121570376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685121870394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122170385,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122470467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685122770415,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123070412,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123370409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123670402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685123970418,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124270399,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124570415,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685124870446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125170457,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125470494,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685125770424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126070436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126370464,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126670446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685126970458,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127270730,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127570540,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685127870479,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128170488,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128470446,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685128770711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129070493,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129370460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129670456,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685129970444,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130270452,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130570463,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685130870454,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131170558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131470459,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685131770480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132070539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132370654,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132670510,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685132970470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133270483,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133570534,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685133870537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134170481,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134470522,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685134770619,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135070468,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135370539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135670470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685135970588,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136270506,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136570482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685136870483,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137170591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137470482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685137770513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138070565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138370612,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138670513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685138970488,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139270567,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139570520,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685139870495,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140170514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140470469,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685140770566,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141070532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141370505,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141670535,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685141970572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142270528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142570539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685142870540,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143170721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143470532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685143770537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144070587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144370585,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144670544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685144970592,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145270578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145570616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685145870578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146170575,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146470586,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685146770618,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147070575,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147370627,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147670593,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685147970600,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148270605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148570644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685148870584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149170590,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149470587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685149770583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150070580,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150370584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150670582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685150970594,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151270632,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151570591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685151870605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152170611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152470611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685152770613,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153070628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153370683,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153670664,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685153970636,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154270611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154570650,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685154870623,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155170939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155470674,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685155770628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156070642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156370678,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156670691,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685156970647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157270649,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157570728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685157870653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158170653,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158470652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685158770755,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159070671,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159370691,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159670661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685159971379,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160270711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160570739,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685160870655,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161170787,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161470703,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685161770668,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162070717,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162371170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162670708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685162970719,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163270676,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163571126,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685163870678,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.77},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164170681,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164470773,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685164771057,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165070675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165370677,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165670713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685165970916,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166270681,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166570684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685166870680,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167171095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167470678,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685167770689,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168070683,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168370787,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168670739,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685168970743,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169270696,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169570699,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685169870784,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170170701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170470695,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685170770757,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171070684,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171370697,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171670698,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685171971138,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172270759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172570699,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685172870711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173170778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173470740,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685173770702,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174070719,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174371094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174670695,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685174970800,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175270722,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175570763,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685175870697,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176170707,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176470754,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685176770748,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177070739,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177370721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177670735,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685177971115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178270740,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.66},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178570747,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685178870774,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179171072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179470822,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685179770758,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180070762,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180370805,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180670780,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685180970809,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181270793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181570900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685181870801,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182170811,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182470860,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685182771048,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183070826,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183370877,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183670882,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685183970939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184270841,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184570853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685184870900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185170967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185470866,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685185770871,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186070870,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186370892,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186670893,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685186970904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187270868,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187572989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685187870872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188170877,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188470913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685188771470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189070899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189370894,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189670921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685189971610,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190270898,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190570940,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685190870918,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191171751,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191470923,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685191770922,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192070981,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192371026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192670934,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685192970954,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193270953,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193571076,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685193870942,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194171071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194470972,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685194770981,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195070960,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:23.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195370975,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195670969,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:23.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685195971032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196270973,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196570982,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685196870986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197171084,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197470984,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685197770988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198070990,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198371020,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198671053,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685198970993,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199271011,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199571046,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685199871115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200171006,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200471008,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685200771192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201071014,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201371067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201671018,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685201971372,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202271010,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202571020,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685202871094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203171957,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203471024,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685203771087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204071079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204372043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204671023,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685204971067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205271028,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205571490,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685205871024,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206171037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206471023,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685206771057,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207071049,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207371039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207671107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685207971068,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208271098,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208571110,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685208871086,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:22.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209171774,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209471092,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685209771092,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210071129,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210371211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210671121,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685210971142,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211271109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211573673,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685211871103,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212171150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212471136,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:21.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685212771652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213071195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:20.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213371188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213671169,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685213971280,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214271228,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214571150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685214871151,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215171157,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215471219,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:19.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685215771223,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216071239,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216371187,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216671220,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685216971167,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217271190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217571385,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685217871202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218171176,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218471193,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685218772083,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219071242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219371182,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219671182,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685219971327,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220271195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220571204,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685220871265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221171213,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221471206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685221771244,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222071214,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222371240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222671231,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685222971227,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223271215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223571642,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685223871216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224171238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224471255,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685224771718,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225071254,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225371225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225671230,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685225971278,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226271229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226571268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685226871228,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227171310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227471236,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685227771233,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228071264,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228371438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228671307,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685228971287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229271247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229571283,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685229871252,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230171240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230471249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685230771547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231071282,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231371247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231671245,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685231971299,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232271267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232571258,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685232871256,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233172128,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233471266,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685233771304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234071280,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234371267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234671308,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685234971294,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235271259,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235573201,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685235871295,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236171262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236471308,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685236772640,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237071263,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237371273,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237671265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685237972838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238271265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238571268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685238871275,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239172611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239471288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685239771274,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240071325,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240372227,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240671318,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685240971329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241271288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241571466,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685241871279,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242171369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242471346,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685242771307,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243071278,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243371329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243671340,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685243971443,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244271334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244571292,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685244871333,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245171537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245471361,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685245771298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246071304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246371537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246671321,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685246971335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247271382,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247571470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685247871384,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248171411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248471353,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685248771403,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249071402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249371376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249671393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685249971493,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250271426,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250571467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685250871415,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251171439,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251471413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685251771409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252071420,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252371615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252671425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685252971434,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253271482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253571596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685253871453,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254171462,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254471470,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685254771721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255071473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255371478,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255671578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685255971776,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256271512,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256571498,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685256871502,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257171620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257471509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685257771511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258071508,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258371764,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258671517,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685258971516,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259271515,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259571742,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685259871562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260171531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260471534,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685260771696,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261071539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261371589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261671538,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685261971867,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262271550,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262571548,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685262871567,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263171794,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263471562,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685263771602,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264071565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264371846,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264671596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685264971615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265271570,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265571596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685265871585,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266171591,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266471584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685266771720,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267071581,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267371587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267671638,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685267971896,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268271589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268571603,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685268871604,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269171897,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269471607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685269771613,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270071662,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270371882,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270671617,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685270971621,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271271686,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271571713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685271871621,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272171630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272471630,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685272771817,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273071635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273371650,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273671673,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685273971701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274271656,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274571692,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685274871686,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275171921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275471665,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685275771698,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276071659,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276371756,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276671662,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685276971675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277271661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277571970,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685277871714,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278171675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278471667,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685278771920,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279071689,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279371671,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279671675,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685279972052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280271668,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280571670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685280871676,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685281671888,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284096032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284395921,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284695933,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685284995930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285295935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285595944,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685285895939,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286195949,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286495951,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685286796009,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287095965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287395953,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287695970,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685287995955,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288295961,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288595996,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685288895968,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289196133,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289495999,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685289795972,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290095973,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290395973,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290695981,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685290996003,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291295989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291595985,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.77},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685291896008,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292196008,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292496041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685292796005,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293096013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293396082,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293696011,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685293996026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294296016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294596031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685294896026,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295196031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295496032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685295796073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296096031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296396105,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296696030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685296996047,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297296080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297596038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685297896041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298196059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298496041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685298796049,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299096058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299396061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299696048,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685299996049,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300296111,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300596061,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685300896068,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301196056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301496064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685301796076,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302096103,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302396063,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302696077,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685302996145,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303296067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303596073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685303896072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304196079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304496103,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685304796082,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305096071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305396094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305696124,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685305996075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306296121,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306596072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685306896081,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307196124,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307496091,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685307797175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308096131,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308396095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308696095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685308996098,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309296119,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309596104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685309896135,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310196123,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310496134,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685310796104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311096115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311396137,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311696121,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685311996202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312296125,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312596146,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685312896148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313196132,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313496203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685313796150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314096147,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314396195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314696202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685314996169,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315296183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315596155,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685315896207,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316196167,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316496181,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685316796216,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317096164,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317396213,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317696170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685317996185,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318296172,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318596191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685318896205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319196165,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319496187,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685319796169,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320096204,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320396170,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320696174,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685320996175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321296205,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321596177,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685321896203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322196246,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322496225,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685322796181,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323096176,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323396175,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323696184,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685323996186,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324296221,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324596190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685324896222,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325196203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325496188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685325796536,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326096185,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326396231,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326696191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685326996194,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327296195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327596190,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685327896227,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328196279,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328496276,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685328796240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329096191,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329396192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329696248,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685329996247,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330296206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330596222,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685330896241,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331196223,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331496227,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685331796287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332096241,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332396262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332696288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685332996282,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333296250,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333596314,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685333896248,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334196250,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334496287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685334796262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335096310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335396322,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335696328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685335996277,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336296341,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336596305,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685336896288,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337196337,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.77},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337496307,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685337796344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.77},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338096310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338396309,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338696313,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685338996338,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339296305,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339596306,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685339896363,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340196325,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340496328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685340796324,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341096323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341396403,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341696331,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685341996329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342296334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342596385,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685342896330,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343196338,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343496342,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685343796354,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344096339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344396346,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344697407,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685344996353,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345296424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345596406,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685345896351,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346196416,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346496410,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685346796378,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347096406,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347396359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347696378,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685347996394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348296366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348596360,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685348896369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349196480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349496365,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685349796376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350096394,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350396369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350696451,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685350996421,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351296370,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351596436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685351896375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352196381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352496379,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685352796390,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353096503,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353396412,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353696392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685353996429,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354296437,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354596450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685354896393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355196401,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355496440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685355796402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356096449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356396391,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356696401,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685356996401,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357296408,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357596403,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685357896429,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358196393,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358496468,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685358796424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359096400,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359396448,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359696410,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685359996404,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360296411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360596442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685360896460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361196442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361496409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685361796427,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362096416,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362396413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362696411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685362996461,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363296411,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363596420,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685363896467,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364196435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364496434,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685364796430,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365096423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365396432,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365696497,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685365996459,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366296423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366596445,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685366896437,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367196433,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367496432,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685367796435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368096426,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368396429,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368696436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685368996438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369296428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369596501,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685369896441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370196509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370496485,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685370796502,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371096455,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371396510,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371696485,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685371996502,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372296476,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372596474,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685372896482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373196484,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373496572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685373796514,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374096510,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374396544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374696519,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685374996566,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375296542,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375596519,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685375896531,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376196570,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376496581,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685376796589,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377096547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377396613,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377696596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685377996542,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378296565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378596624,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685378896627,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379196643,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379496586,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685379796637,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380096596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380396635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380696607,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685380996713,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381296598,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381596615,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685381896608,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382196647,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382496621,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685382796622,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383096636,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383396656,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383696677,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685383996640,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384296634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384596702,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685384896755,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385196657,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385496648,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685385796721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386096661,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386396764,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386696644,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685386996711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387296665,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387596687,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685387896719,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388196746,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388496677,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685388796728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389096728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389396772,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389696700,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685389996694,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390296741,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390596769,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685390896706,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391196708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391496778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685391796848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392096805,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392396723,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392696723,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685392996799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393296731,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393596725,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685393896759,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394196778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394496727,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685394796838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395096733,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395396756,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395696744,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685395996738,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396296745,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396596863,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685396896748,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397196744,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397496752,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685397797031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398096745,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398396778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398696753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685398996882,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399296749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399596872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685399896856,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400196853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400496758,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685400796806,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401096749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401396853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401696823,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685401996749,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402296834,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402596862,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685402896766,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403196764,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403496778,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685403796902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404096775,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404396829,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404696790,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685404996816,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405296883,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405596870,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685405896793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406196983,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406496794,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685406796799,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407096806,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407396889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407696814,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685407996818,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408296823,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408596913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685408896867,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409196827,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409496885,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685409796923,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410096833,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410396863,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410696853,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685410996931,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411296850,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411596860,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685411896863,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412197065,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412496865,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685412796871,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413096914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413396986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413696881,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685413996886,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414296923,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414597013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685414896976,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415196895,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415496889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685415796967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416096899,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416396952,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416696900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685416997056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417296914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417596918,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685417896941,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418197072,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418496972,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685418796976,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419096917,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419397122,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419696925,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685419996981,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420296927,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420597159,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685420896981,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421196938,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421496968,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685421797058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422096935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422397004,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422696956,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685422997188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423296955,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423597001,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685423896956,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424197012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424497000,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685424796971,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425096964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425397109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425696964,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.02},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685425996974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426296965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426597100,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685426896989,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427196988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427497031,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685427797156,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428097083,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428396991,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428696996,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685428997105,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429296992,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429597030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685429896994,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430197076,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430497010,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685430796999,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431097007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431397249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431697002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685431997013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432297009,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432597030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685432897132,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433197016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433497009,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685433797139,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434097016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434397064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434697027,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685434997238,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435297077,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435597014,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685435897071,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436197195,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436497013,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685436797015,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437097050,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437397237,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437697030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685437997069,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438297034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438597203,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685438897033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439197064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439497033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685439797107,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440097051,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440397038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440697073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685440997179,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441297048,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441597041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685441897039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442197094,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442497030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685442797045,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443097030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443397349,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443697027,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685443997092,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444297033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.77},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444597073,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.68},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685444897078,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445197034,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445497068,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685445797209,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446097058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446397051,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446697059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685446997166,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447297115,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447597112,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685447897089,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.41},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448197159,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.74},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448497098,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685448797127,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449097105,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449397373,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449697109,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685449997136,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450297128,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450597387,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685450897183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451197144,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451497142,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685451797185,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452097148,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452397249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452697161,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685452997474,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453297206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453597173,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685453897183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454197215,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454497192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685454797260,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455097202,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455397476,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455697209,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685455997240,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456297262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456597249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685456897228,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457197269,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457497236,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685457797465,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458097286,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458397242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458697267,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685458997286,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459297248,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459597268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685459897263,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460197357,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460497301,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685460797266,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461097305,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461397544,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461697280,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685461997291,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462297287,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462597465,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685462897303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.35},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685463197366,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685463737229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464037277,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464337245,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464637256,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685464937262,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465237316,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465537294,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685465837334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466137337,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466437310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685466737354,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467037407,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467337326,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467637328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685467937333,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468237339,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468537360,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685468837368,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469137413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469437370,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685469737372,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470037427,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470337392,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470637406,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685470937407,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.69},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471237416,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471537421,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685471837423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472137555,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472437434,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685472737439,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473037727,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473337523,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473637452,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685473937500,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474237504,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474537449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685474837471,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475137479,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475437511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685475737497,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476037496,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476337572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476637511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685476937513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477237528,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477537526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685477837530,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478137582,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478437532,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685478737565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479037545,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479337555,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479637566,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.56},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685479937595,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480237565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480537635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685480837564,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481137578,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.27},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481437654,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.32},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685481737583,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.24},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482037634,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482337596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482637588,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685482937605,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483237606,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483537617,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685483837694,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484137652,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484437620,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685484737629,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485037682,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485337673,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485637637,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685485937698,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486237666,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486537695,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.4},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685486837701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487137670,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487437690,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685487737711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488037671,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488337728,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488637752,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685488937679,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.06},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489237735,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.04},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489537691,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685489837848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490137701,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490437705,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685490737730,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491037756,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491337708,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491637705,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685491937711,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492237764,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492537769,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685492837718,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493137753,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493437930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685493737724,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.87},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494037777,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494337747,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494637852,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685494937737,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495237777,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495537775,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685495837812,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496137755,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496437796,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685496737809,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497037761,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497337761,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497637765,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685497937814,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498237807,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498537788,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685498837775,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499137789,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499437805,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685499737817,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500037780,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500337844,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500637891,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685500937793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501237793,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501537807,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685501837925,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502137801,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502437811,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685502737895,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503037900,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503337808,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503637807,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685503937812,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504237850,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504537822,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685504837872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505137866,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505438032,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685505737834,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506037879,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506337861,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506637914,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685506937872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507237889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507537838,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685507837888,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508137887,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508437832,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685508737867,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509037974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509337857,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509637848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685509937889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510237947,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.62},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510537889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685510837852,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511137855,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.65},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511437965,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685511737859,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512037848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512337852,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512638025,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685512937857,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513237850,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513537848,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685513837893,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514137857,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514437855,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685514737977,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515037889,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515337874,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515637865,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685515937961,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516238059,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516537872,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685516837969,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517137902,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517437997,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685517737887,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518037974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518337895,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518637932,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685518937904,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519238002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519537959,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685519837988,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520137912,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520437906,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.37},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685520737913,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521038006,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521337908,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521637915,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685521937963,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522238080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522537924,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685522837919,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523137944,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.5},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523438045,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685523737930,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524037929,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524337974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524638007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685524937934,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525237935,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.95},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525537943,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685525838078,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526137951,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526437950,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.99},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685526737944,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527038721,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527338012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527637961,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685527937952,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528238080,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528537978,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685528837960,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529137967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.08},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529438131,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685529738016,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530037967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530337963,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530638067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685530937995,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531237967,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531537979,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685531838029,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532137972,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532437974,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685532738070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533038022,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.92},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533338038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533637982,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685533938045,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534238057,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534537980,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685534838036,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535137993,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535438136,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685535737984,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536037986,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536337985,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536638024,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685536938025,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537237999,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537538002,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685537838106,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.91},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538138007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.82},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538438058,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685538738048,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539038104,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.28},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539338007,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539638019,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685539938003,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540238052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540538039,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685540838017,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541138064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541438054,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685541738229,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542038012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.22},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542338042,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542638126,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685542938012,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543238056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:18.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543538110,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685543838052,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544138125,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544438027,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:17.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685544738110,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.96},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545038075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545338027,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545638075,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685545938022,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.63},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546238174,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546538079,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685546838020,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547138129,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547438095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685547738125,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548038046,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548338056,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.9},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548638087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685548938038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549238040,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549538033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685549838168,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550138087,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:15.03},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550438030,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685550738120,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551038139,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:14.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551338037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551638033,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.49},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685551938041,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552238174,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552538043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685552838043,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553138067,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553438546,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685553738055,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.52},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554038140,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554338045,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554638134,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685554938070,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.16},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555238057,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555538064,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685555838093,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556138085,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556438188,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685556738092,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557038192,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557338095,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.01},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557638182,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685557938150,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558238172,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.61},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558538110,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685558838201,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559138123,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559438206,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.59},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685559738189,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560038129,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560338155,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.57},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560638404,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685560938173,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561238169,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561538183,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685561838237,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562138233,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.21},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562438249,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685562738211,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563038228,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563338214,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563638217,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685563938231,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564238362,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564538381,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685564838277,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565138242,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565438280,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685565738251,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566038259,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566338265,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566638303,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685566938268,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567238323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567538343,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685567838304,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568138281,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568438336,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685568738284,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569038329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569338310,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569638302,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685569938300,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.25},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570238298,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570538297,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685570838294,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.97},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571138323,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571438384,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685571738313,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572038419,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572338315,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572638324,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685572938327,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573238329,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573538333,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685573838369,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574138332,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574438328,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685574738335,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575038372,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575338334,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575638376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.44},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685575938389,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.48},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576238419,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.39},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576538344,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685576838359,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.2},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577138380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577438375,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685577738413,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578038361,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.29},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578338371,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.3},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578638503,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685578938376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.18},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579238383,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579538380,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685579838438,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.13},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580138376,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580438398,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685580738405,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581038616,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581338395,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581638435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.94},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685581938409,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582238480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582538402,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685582838405,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583138415,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583438613,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685583738415,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584038410,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584338448,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584638454,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685584938414,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585238420,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.98},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585538423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685585838440,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.89},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586138428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586438423,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685586738424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587038648,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587338431,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587638450,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.79},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685587938475,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588238559,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588538441,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.88},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685588838584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589138428,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.58},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589438536,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685589738473,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590038433,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590338478,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.67},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590638761,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685590938425,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591238442,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591538439,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685591838504,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.31},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592138436,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592438435,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685592738487,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593038723,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593338444,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.38},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593638424,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685593938457,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.34},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594238655,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594538452,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685594838449,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595138489,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595438547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.84},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685595738460,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.78},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596038492,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596338571,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596638545,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685596938457,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.76},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597238477,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.85},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597538472,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685597838494,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.83},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598138501,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:9.86},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598438509,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685598738535,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599038819,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599338484,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599638529,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685599938480,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.14},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600238698,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.23},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600538482,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.1},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685600838527,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601138487,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601438740,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685601738547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.45},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602038498,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602338488,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.43},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602638682,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685602938581,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.46},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603238508,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603538503,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685603838572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604138511,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.47},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604438579,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685604738515,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605038560,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:10.55},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605338556,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605638563,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685605938519,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606238594,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606538513,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.12},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685606838518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607138518,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607438879,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685607738543,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.19},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608038530,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.42},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608338527,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608638628,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.33},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685608938572,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609238526,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609538568,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685609838674,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610138530,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.54},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610438525,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685610738604,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611038666,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.81},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611338564,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:11.72},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611638584,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685611938537,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612238596,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.09},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612538547,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685612838540,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.11},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613138539,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613438767,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.53},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685613738611,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614038551,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.51},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614338551,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614638741,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685614938559,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:12.64},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615238587,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.05},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615538593,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.15},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685615838836,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616138551,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.07},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616438549,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.17},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685616738558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617038760,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.26},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617338558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617638534,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.36},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685617938635,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.73},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618238566,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618538558,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.71},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685618838593,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619138565,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.75},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619438673,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.93},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1685619738585,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:13.93}]],&#92;&#92;&#92;&quot;labels&#92;&#92;&#92;&quot;:[&#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot;]}]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3eb08d4843164efc&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;41e847ff22249c0e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Temperature&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;1d985094b1a81b0c&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;24&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;1d985094b1a81b0c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Wide View&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow163.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-163&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;3.-using-sliders-and-persisting-the-current-value&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/06/3-quick-node-red-tips-7/#3.-using-sliders-and-persisting-the-current-value&quot;&gt;3. Using sliders and persisting the current value&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sliders are a really useful user-interface element. Where you need to control the speed of a piece of machinery, having the ability to use a slider rather than manually typing in a value is a much better fit for shop-floor HMIs.&lt;/p&gt;
&lt;p&gt;When using sliders in your dashboards, it&#39;s important to consider how you will persist the state of the slider. If you don&#39;t persist the state, you will find that a redeploy of your dashboard will set the slider back to the default value. That would also change the speed of your machine.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;An example of a slider in a HMI&quot; alt=&quot;An example of a slider in a HMI&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/slider-ui.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To retain the current value of the slider we can use Node-RED&#39;s context. Each time the slider value is updated, we store the value in context. Each time we deploy the flow, we can now load the value back from context.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to view this slider and the flow which makes it work on your own Node-RED, you can import the flow below.&lt;/p&gt;
&lt;div id=&quot;nr-flow-164&quot; style=&quot;height: 300px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow164 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;05340e7a133098a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_slider&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0e6be5088cecccc1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;tooltip&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;41e847ff22249c0e&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;passthru&#92;&quot;:true,&#92;&quot;outs&#92;&quot;:&#92;&quot;all&#92;&quot;,&#92;&quot;topic&#92;&quot;:&#92;&quot;topic&#92;&quot;,&#92;&quot;topicType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;min&#92;&quot;:0,&#92;&quot;max&#92;&quot;:&#92;&quot;20&#92;&quot;,&#92;&quot;step&#92;&quot;:1,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:230,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;945db61c94fc0704&#92;&quot;,&#92;&quot;ad7819da2cfbcd4e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;849d76d146ff8c12&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0e6be5088cecccc1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Inject on deploy&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:160,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;aeedb3c60965c1af&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;945db61c94fc0704&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0e6be5088cecccc1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set global-slider-value = msg.payload&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;slider-value&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:450,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;aeedb3c60965c1af&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0e6be5088cecccc1&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Set msg.payload = global.slider-value&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;slider-value&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;global&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:410,&#92;&quot;y&#92;&quot;:240,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;05340e7a133098a6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad7819da2cfbcd4e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_text&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0e6be5088cecccc1&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;41e847ff22249c0e&#92;&quot;,&#92;&quot;order&#92;&quot;:2,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;label&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;The current value is  meters per minute&#92;&quot;,&#92;&quot;layout&#92;&quot;:&#92;&quot;row-spread&#92;&quot;,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;style&#92;&quot;:false,&#92;&quot;font&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;fontSize&#92;&quot;:16,&#92;&quot;color&#92;&quot;:&#92;&quot;#000000&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:340,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;41e847ff22249c0e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Meters per Minute&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;466e33abb95e4dd4&#92;&quot;,&#92;&quot;order&#92;&quot;:5,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;466e33abb95e4dd4&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Sliders&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;order&#92;&quot;:3,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow164.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-164&#39;) })&lt;/script&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;. You can also read some of our previous Node-RED tips using the links below.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/&quot;&gt;Node-RED Tips - Subflows, Link Nodes, and the Range Node&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/&quot;&gt;Node-RED Tips - Importing, Exporting, and Grouping Flows&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/&quot;&gt;Node-RED Tips - Smooth, Catch, and Maths&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/&quot;&gt;Node-RED Tips - Exec, Filter, and Debug&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/&quot;&gt;Node-RED Tips - Deploying, Debugging, and Delaying&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/&quot;&gt;Node-RED Tips - Wiring Shortcuts&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/node-red-community-survey-results/</id>
        <title>Node-RED Community Survey Results</title>
        <summary>Discover the trends and insights into the Node-RED community</summary>
        <updated>2023-05-31T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/node-red-community-survey-results/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The Node-RED community recently published the results of their &lt;a href=&quot;https://nodered.org/about/community/survey/2023/&quot;&gt;2023 Community Survey&lt;/a&gt;, building upon their &lt;a href=&quot;https://nodered.org/about/community/survey/2019/&quot;&gt;2019 survey&lt;/a&gt;. The findings reveal some interesting trends within the Node-RED community that are worth highlighting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Passionate and Experienced Community&lt;/strong&gt;. The Node-RED community has shown a remarkable increase in experience. In 2019, only 28.3% of users had been utilizing Node-RED for over two years. However, in 2023, this number has grown to an impressive 65.2%. This indicates that Node-RED has become a go-to tool for many individuals, demonstrating their continued loyalty to the platform. Moreover, the community highly regards Node-RED, with 94% of respondents rating it as a 4 or 5 on a scale of 1 to 5.&lt;/p&gt;
&lt;p&gt;Developer tools can fall out of fashion but it is clear Node-RED is providing value and is being used by developers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increasing Adoption in Industrial and Manufacturing Automation&lt;/strong&gt;. The survey also revealed a significant increase in Node-RED usage within the manufacturing and industrial automation industries. Several data points support this finding, including a rise from 31.5% to 40.3% in respondents identifying themselves as working in the manufacturing industry. Additionally, there has been an increase in the use of Node-RED applications for Industrial IoT/PLC devices, which grew from 24% to 35.8% in 2023. Furthermore, the adoption of popular manufacturing industry protocols like &lt;a href=&quot;https://opcfoundation.org/&quot;&gt;OPC-UA&lt;/a&gt; and &lt;a href=&quot;https://modbus.org/&quot;&gt;Modbus&lt;/a&gt; has also increased, with OPC-UA usage rising from 9.3% to 16.7% and Modbus usage increasing from 15.8% to 27.6%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;InfluxDB dominance in the Node-RED community&lt;/strong&gt;.&lt;a href=&quot;https://www.influxdata.com/&quot;&gt; InfluxDB&lt;/a&gt; has emerged as the leading database within the Node-RED community. Its usage has grown significantly, from 24.2% in 2019 to 43.9% in 2023. On the other hand, MySQL, the next most popular database, experienced a slight decrease in usage, dropping from 32.4% to 31.4%.&lt;/p&gt;
&lt;p&gt;It is evident that the MING stack (MQTT/Mosquitto, InfluxDB, Node-RED, and Grafana) is gaining momentum and becoming a preferred choice for developers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Limitations to Node-RED Adoption&lt;/strong&gt;. This year&#39;s survey also explored factors that might limit the adoption of Node-RED. Approximately 27.9% of respondents stated that they perceived no additional need for Node-RED. However, the next most common responses were related to the perception that Node-RED is only suitable for proof-of-concept (POC) projects (19.9%), the lack of specific Node-RED features (13.3%), and the absence of professional support (10.1%).&lt;/p&gt;
&lt;p&gt;It is important for the Node-RED community to demonstrate the platform&#39;s usage in production environments. Although changing the perception of Node-RED as solely a POC tool may take time, FlowFuse is committed to helping shift this perspective. Moreover, FlowFuse aims to address other identified issues by developing the FlowFuse platform, which will provide the necessary features to create reliable, secure, and dependable Node-RED applications. FlowFuse will also offer professional support to all its customers, ensuring that users have the assistance they need.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thank you to everyone that completed the Node-RED Survey. The insights from the survey will help the community to build a better Node-RED. Check out the detailed results on the &lt;a href=&quot;https://nodered.org/about/community/survey/2023/&quot;&gt;nodered.org website&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/</id>
        <title>Persisting chart data in Node-RED Dashboard 1</title>
        <summary>Keep your historic chart data safe and available</summary>
        <updated>2023-05-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Node-RED makes it easy to create HMI (Human Machine Interfaces) using &lt;a href=&quot;https://flows.nodered.org/node/node-red-dashboard&quot;&gt;Node-RED Dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the most useful features of Dashboard 1 is the ability to store historic data passed to a chart within the chart node itself. This makes your flows far simpler than would be the case if you needed to send the entire data set to the chart for each update.&lt;/p&gt;
&lt;div class=&quot;blog-update-notes&quot;&gt;
    &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; Since this article was published, Node-RED Dashboard (1.0) has been &lt;a href=&quot;https://discourse.nodered.org/t/announcement-node-red-dashboard-v1-deprecation-notice/89006&quot; target=&quot;_blank&quot;&gt;deprecated&lt;/a&gt;.&lt;/p&gt;
    &lt;p&gt;Instead, it is recommended to use &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;FlowFuse Dashboard (Dashboard 2.0)&lt;/a&gt; which is a more modern and feature-rich dashboard solution for Node-RED.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;the-importance-of-persisting-chart-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#the-importance-of-persisting-chart-data&quot;&gt;The Importance of Persisting Chart Data&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Storing the data in the chart node is fine to show prototypes of HMIs, but where it&#39;s vital the correct data is always shown we are going to need a backup. Data can easily be lost when you move your flow to a new device, restart your instance, or simply when upgrading Node-RED.&lt;/p&gt;
&lt;p&gt;How can we store our chart data so we can be confident it will be there each time a user views your HMI?&lt;/p&gt;
&lt;h3 id=&quot;example-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#example-dashboard&quot;&gt;Example Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this example, we are passing in a random number between one and 10 each second. With each new value received the chart updates and as mentioned about, the values are also stored in the chart node.&lt;/p&gt;
&lt;p&gt;If you&#39;d like to see and edit the flows I&#39;ve created, you can copy and paste the JSON below into your Node-RED import feature.&lt;/p&gt;
&lt;div id=&quot;nr-flow-155&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow155 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c6825b1001216b89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b609d978540fb2a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b609d978540fb2a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;794846db6dc8cef8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;794846db6dc8cef8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad53848ee4b0d91e&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad53848ee4b0d91e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:220,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow155.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-155&#39;) })&lt;/script&gt;
x
### How can we store and recall the chart data?
&lt;p&gt;The chart node has a really useful feature which allows us to access all the data currently shown in the chart. Each time the chart receives new data, it&#39;s added to the existing values then the whole data set is sent out the outbound port of the chart node.&lt;/p&gt;
&lt;p&gt;Now that we have a way to easily access the chart data in a single payload, we next need to store that data somewhere safer. I&#39;m going to explain 3 potential solutions, which I use on a regular basis.&lt;/p&gt;
&lt;h4 id=&quot;1.-node-red-file-out-and-file-in-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#1.-node-red-file-out-and-file-in-nodes&quot;&gt;1. Node-RED file-out and file-in nodes&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Node-RED can read and write data to a local filesystem. Being that we already have the chart data in a single payload, we just need to write that payload to a file for later use, which we can do using the file-out node.&lt;/p&gt;
&lt;p&gt;This example flow shows how to use the file-out node to write the chart data to your local filesystem.&lt;/p&gt;
&lt;div id=&quot;nr-flow-156&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow156 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ead9df683d29fb8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ef5359b8bd3f78b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef5359b8bd3f78b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;69ad440cd8d1ce30&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;69ad440cd8d1ce30&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e4e7758028477505&#92;&quot;,&#92;&quot;d9d6a2e34767f568&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e4e7758028477505&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9d6a2e34767f568&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pretty&#92;&quot;:false,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5b020fb17f615df&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5b020fb17f615df&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;example.json&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a6d9eab41d4dcf97&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a6d9eab41d4dcf97&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 92&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow156.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-156&#39;) })&lt;/script&gt;
&lt;p&gt;As the chart node sends the full data set each time new data is added, we overwrite the content of the file rather than append the new values.&lt;/p&gt;
&lt;p&gt;The next step is to pull the data back from the filesystem to your Node-RED instance. Node-RED makes this very easy using the file-in node.&lt;/p&gt;
&lt;div id=&quot;nr-flow-157&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow157 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;ead9df683d29fb8a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ef5359b8bd3f78b3&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ef5359b8bd3f78b3&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;69ad440cd8d1ce30&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;69ad440cd8d1ce30&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:430,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;e4e7758028477505&#92;&quot;,&#92;&quot;d9d6a2e34767f568&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e4e7758028477505&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:560,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9d6a2e34767f568&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;pretty&#92;&quot;:false,&#92;&quot;x&#92;&quot;:550,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b5b020fb17f615df&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b5b020fb17f615df&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;example.json&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;appendNewline&#92;&quot;:true,&#92;&quot;createDir&#92;&quot;:false,&#92;&quot;overwriteFile&#92;&quot;:&#92;&quot;true&#92;&quot;,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;x&#92;&quot;:690,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a6d9eab41d4dcf97&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a6d9eab41d4dcf97&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 92&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;e9cb9350f1aaeb38&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;import data&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:110,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;600f014947f73d8f&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;600f014947f73d8f&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;example.json&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;utf8&#92;&quot;,&#92;&quot;chunk&#92;&quot;:false,&#92;&quot;sendError&#92;&quot;:false,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;allProps&#92;&quot;:false,&#92;&quot;x&#92;&quot;:270,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;972118c0e114f47b&#92;&quot;,&#92;&quot;69ad440cd8d1ce30&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;972118c0e114f47b&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;668c56888fd0f960&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 93&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:420,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow157.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-157&#39;) })&lt;/script&gt;
&lt;p&gt;When you press the &#39;import data&#39; trigger node, the data is loaded in from the filesystem and shown in the chart. You may want to automate that task to run each you deploy your Node-RED instance.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Import data on deploy&quot; alt=&quot;Import data on deploy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/inject-on-deploy.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Bear in mind that your data is stored in your filesystem, if your storage drive fails you will lose your data, you might want to consider taking backups and storing elsewhere for emergencies.&lt;/p&gt;
&lt;h4 id=&quot;2.-flowfuse&#39;s-persistent-context&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#2.-flowfuse&#39;s-persistent-context&quot;&gt;2. FlowFuse&#39;s persistent context&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;FlowFuse Cloud and premium self hosted version provides persistent context storage as part of its Node-RED instances. This allows you to create, read, update, and delete data as needed, even if you have restarted a Node-RED instance.&lt;/p&gt;
&lt;p&gt;This flow shows chart data being sent to persistent context so we can access it later. The process is very similar to using the file-out and file-in nodes.&lt;/p&gt;
&lt;div id=&quot;nr-flow-158&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow158 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c6825b1001216b89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b609d978540fb2a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;794846db6dc8cef8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad53848ee4b0d91e&#92;&quot;,&#92;&quot;938c7d878545e623&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad53848ee4b0d91e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b609d978540fb2a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;794846db6dc8cef8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;938c7d878545e623&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;#:(persistent)::chart-data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3792cc96a748e75a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3792cc96a748e75a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow158.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-158&#39;) })&lt;/script&gt;
&lt;p&gt;We now need to have a method to load the data back into our chart. We will again use a manual &#39;import data&#39; trigger to load the full set of data from the persistent context, and then push it back into the chart.&lt;/p&gt;
&lt;div id=&quot;nr-flow-159&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow159 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;c6825b1001216b89&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;6b609d978540fb2a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;794846db6dc8cef8&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:490,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ad53848ee4b0d91e&#92;&quot;,&#92;&quot;938c7d878545e623&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ad53848ee4b0d91e&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:610,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;6b609d978540fb2a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:330,&#92;&quot;y&#92;&quot;:100,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;794846db6dc8cef8&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;938c7d878545e623&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;#:(persistent)::chart-data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;global&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:660,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;3792cc96a748e75a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3792cc96a748e75a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 1&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:840,&#92;&quot;y&#92;&quot;:140,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;3379276c77b4691c&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;import data&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ddd1ef41321fb4a6&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ddd1ef41321fb4a6&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;#:(persistent)::chart-data&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;global&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:320,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;794846db6dc8cef8&#92;&quot;,&#92;&quot;fa65b958e34bc971&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;fa65b958e34bc971&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 2&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:480,&#92;&quot;y&#92;&quot;:180,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow159.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-159&#39;) })&lt;/script&gt;
&lt;p&gt;You may have noticed that when we are pushing duplicate data into the chart it automatically checks to see if the data is already stored. If the data points are already in the chart the new data is disregard. This saves us writing an extra section of the flow to delete the data before we load it in.&lt;/p&gt;
&lt;h4 id=&quot;3.-expose-the-data-via-an-api-then-manually-import-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#3.-expose-the-data-via-an-api-then-manually-import-it&quot;&gt;3. Expose the data via an API then manually import it&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In some cases you may want to copy your chart data to somewhere outside of your Node-RED instances. You can do this by creating a simple API which allows an outside system to request the chart data. You can also manually go to the URL of the API in a web browser to get your data. This example flow allows a user or system to access the chart data via a URL.&lt;/p&gt;
&lt;div id=&quot;nr-flow-160&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow160 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6523e86042252710&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d51aba5f9a808592&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;427c60f2c4f523b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ba84cd1820120139&#92;&quot;,&#92;&quot;d9087436f4769691&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba84cd1820120139&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d51aba5f9a808592&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;427c60f2c4f523b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9087436f4769691&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;chart-data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4dd97b29430ad2ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;/data&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;get&#92;&quot;,&#92;&quot;upload&#92;&quot;:false,&#92;&quot;swaggerDoc&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4f0eb085cc91834&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7ca49e5465699355&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusCode&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;headers&#92;&quot;:{},&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4f0eb085cc91834&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get the chart data from flow.chart-data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;chart-data&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:640,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7ca49e5465699355&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow160.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-160&#39;) })&lt;/script&gt;
&lt;p&gt;We can now access the data by simply visiting the URL of the API.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The chart data accessed via the API in a web browser&quot; alt=&quot;The chart data accessed via the API in a web browser&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/data-in-browser.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Bear in mind that you should secure the API as appropriate for the data. If you don&#39;t put security around the API, anyone on the same network as your Node-RED instance can access your chart data. Potentially that could give access to our data to the whole internet, so where needed take steps to keep your data safe. You can read more about securing Node-RED in our &lt;a href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/&quot;&gt;blog post here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We now need to get that data back into a Node-RED instance. We can do that by editing a node and pasting in the data we got from the API. The flow below shows where you can paste in your data, you will then need to deploy and manually trigger &#39;import data&#39;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Inject the data in JSON format&quot; alt=&quot;Inject the data in JSON format&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/inject-the-json.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;div id=&quot;nr-flow-161&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow161 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6523e86042252710&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:150,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d51aba5f9a808592&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;427c60f2c4f523b7&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_chart&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;group&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;order&#92;&quot;:0,&#92;&quot;width&#92;&quot;:0,&#92;&quot;height&#92;&quot;:0,&#92;&quot;label&#92;&quot;:&#92;&quot;chart&#92;&quot;,&#92;&quot;chartType&#92;&quot;:&#92;&quot;line&#92;&quot;,&#92;&quot;legend&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;xformat&#92;&quot;:&#92;&quot;HH:mm:ss&#92;&quot;,&#92;&quot;interpolate&#92;&quot;:&#92;&quot;linear&#92;&quot;,&#92;&quot;nodata&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;dot&#92;&quot;:false,&#92;&quot;ymin&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;ymax&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlder&#92;&quot;:1,&#92;&quot;removeOlderPoints&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;removeOlderUnit&#92;&quot;:&#92;&quot;3600&#92;&quot;,&#92;&quot;cutout&#92;&quot;:0,&#92;&quot;useOneColor&#92;&quot;:false,&#92;&quot;useUTC&#92;&quot;:false,&#92;&quot;colors&#92;&quot;:[&#92;&quot;#1f77b4&#92;&quot;,&#92;&quot;#aec7e8&#92;&quot;,&#92;&quot;#ff7f0e&#92;&quot;,&#92;&quot;#2ca02c&#92;&quot;,&#92;&quot;#98df8a&#92;&quot;,&#92;&quot;#d62728&#92;&quot;,&#92;&quot;#ff9896&#92;&quot;,&#92;&quot;#9467bd&#92;&quot;,&#92;&quot;#c5b0d5&#92;&quot;],&#92;&quot;outputs&#92;&quot;:1,&#92;&quot;useDifferentColor&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:470,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;ba84cd1820120139&#92;&quot;,&#92;&quot;d9087436f4769691&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;ba84cd1820120139&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:590,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d51aba5f9a808592&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;Number&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Random Number&#92;&quot;,&#92;&quot;minimum&#92;&quot;:&#92;&quot;1&#92;&quot;,&#92;&quot;maximum&#92;&quot;:&#92;&quot;10&#92;&quot;,&#92;&quot;roundTo&#92;&quot;:&#92;&quot;0&#92;&quot;,&#92;&quot;Floor&#92;&quot;:true,&#92;&quot;x&#92;&quot;:310,&#92;&quot;y&#92;&quot;:540,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;427c60f2c4f523b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d9087436f4769691&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;chart-data&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;flow&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;msg&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:630,&#92;&quot;y&#92;&quot;:580,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;4dd97b29430ad2ba&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;url&#92;&quot;:&#92;&quot;/data&#92;&quot;,&#92;&quot;method&#92;&quot;:&#92;&quot;get&#92;&quot;,&#92;&quot;upload&#92;&quot;:false,&#92;&quot;swaggerDoc&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:200,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b4f0eb085cc91834&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;7ca49e5465699355&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;http response&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusCode&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;headers&#92;&quot;:{},&#92;&quot;x&#92;&quot;:670,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b4f0eb085cc91834&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Get the chart data from flow.chart-data&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;chart-data&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;flow&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:440,&#92;&quot;y&#92;&quot;:660,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;7ca49e5465699355&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;d13d16b33ec638b2&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;4767c2f7095bee53&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;import data&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:true,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;[{&#92;&#92;&#92;&quot;series&#92;&#92;&#92;&quot;:[&#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot;],&#92;&#92;&#92;&quot;data&#92;&#92;&#92;&quot;:[[{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1684841975036,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:8},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1684841976037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:6},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1684841977038,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7},{&#92;&#92;&#92;&quot;x&#92;&#92;&#92;&quot;:1684841978037,&#92;&#92;&#92;&quot;y&#92;&#92;&#92;&quot;:7}]],&#92;&#92;&#92;&quot;labels&#92;&#92;&#92;&quot;:[&#92;&#92;&#92;&quot;&#92;&#92;&#92;&quot;]}]&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;json&#92;&quot;,&#92;&quot;x&#92;&quot;:170,&#92;&quot;y&#92;&quot;:600,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;427c60f2c4f523b7&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;af1535b39b74f94a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_group&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Example&#92;&quot;,&#92;&quot;tab&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;order&#92;&quot;:1,&#92;&quot;disp&#92;&quot;:true,&#92;&quot;width&#92;&quot;:&#92;&quot;6&#92;&quot;,&#92;&quot;collapse&#92;&quot;:false,&#92;&quot;className&#92;&quot;:&#92;&quot;&#92;&quot;},{&#92;&quot;id&#92;&quot;:&#92;&quot;14f1442eb7525190&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;ui_tab&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Home&#92;&quot;,&#92;&quot;icon&#92;&quot;:&#92;&quot;dashboard&#92;&quot;,&#92;&quot;disabled&#92;&quot;:false,&#92;&quot;hidden&#92;&quot;:false}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow161.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-161&#39;) })&lt;/script&gt;
&lt;p&gt;Each of these solutions has strengths and weaknesses but there are many other ways to persist your chart data. You should consider which approach is the best fit for your needs. To be as confident as possible that you data is safe, you may decide to push your data to dedicate external storage such as a database or backup solution.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/persisting-chart-data-in-node-red/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED Dashboard 1 allows you to easily make informative HMIs, but it&#39;s important to make sure the chart data you are showing is stored safely. The approaches we have discussed above should give you a good start in ensuring your charts are populated with the correct data, even if your Node-RED instance crashes or you need to move it to a new hosting location.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/</id>
        <title>Best Practices Integrating a Modbus Device With Node-RED</title>
        <summary>Integrate Modbus with Node-RED</summary>
        <updated>2023-05-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The world of industrial automation is slow to adopt new technology. With legacy equipment already working and in place, paralyzing down-time costs, and fears of introducing instability into a plant, technology change has a cautious pace.&lt;/p&gt;
&lt;p&gt;Node-RED provides a way to extend the capabilities of the simpler, proven technology, allowing connections with modern systems.  However, the same fundamentals that have made industrial equipment dependable, must be incorporated into your Node-RED architecture.  And, inversely, the same abstraction and simplicity that makes a low-code, Node-RED environment fast, and easy to work with, can also make it difficult to interface with a lower-level system.&lt;/p&gt;
&lt;p&gt;Modbus is a widely adopted protocol for accessing data from existing legacy manufacturing equipment. Node-RED makes it very easy to connect to Modbus enabled equipment. However, there are some best practices we have developed to maintain system integrity when integrating Modbus devices with Node-RED:&lt;/p&gt;
&lt;h3 id=&quot;add-watchdogs-to-node-red-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#add-watchdogs-to-node-red-flows&quot;&gt;Add Watchdogs to Node-RED Flows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To keep your automation system running with peace of mind and little human intervention, use a watchdog timer.  A watchdog timer is typically used to detect and recover from system malfunctions. In Node-RED a watchdog timer can be tied to a broadcast messaging system to get push alerts directly to cell phones, as well as to an auto-reset to try to get your Flows back online automatically.  A simple implementation of this is to just put two Trigger nodes in a loop, the first one to send an alert when it hasn’t seen any recent events, and the second to to reset the first one.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example watchdog flow&quot; alt=&quot;Example watchdog flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Each of the trigger nodes are setup with similar parameters, only the delay values differ.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Trigger node configuration&quot; alt=&quot;Trigger node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-14.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Sending a payload of {&amp;quot;connectorType&amp;quot;:&amp;quot;TCP&amp;quot;} to the Modbus Flex Connector is enough to reset the connection without needing to send all the other parameters.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Change node configuration&quot; alt=&quot;Change node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-10.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;choosing-a-safe-poll-rate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#choosing-a-safe-poll-rate&quot;&gt;Choosing a Safe Poll Rate&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Be careful when adding new traffic to an industrial network, which might not be able to handle the extra load.  Some networks have low-bandwidth, especially at large plants that might be using antiquated IP devices and long-distance, Wi-Fi bridges in electrically noisy environments.  Furthermore, some PLCs and other Modbus devices have limits as to how many other devices can connect to them, and a new connection might not work, or worse, bump off an old connection.  A PLC’s general operation is to poll its inputs every cycle and react accordingly, running logic and triggering outputs as quickly as possible. The general use-case for Node-RED with a PLC is to create an HMI or broader, SCADA system.  A poll rate of every second suffices for a simple HMI.  For dashboards published to a greater audience, rather than just the operator, poll rates of several minutes to hours might be adequate.  If this is a new integration, it’s better to start slow and make sure the current infrastructure can handle the extra load.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Modbus node configuration&quot; alt=&quot;Modbus node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-7.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;coil%2Fregister-grouping&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#coil%2Fregister-grouping&quot;&gt;Coil/Register Grouping&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modbus works more efficiently when it is reading and writing addresses as groups.  Creating banks of consecutively numbered coils or registers can help with this.  If Modbus is already in use, perhaps for an existing HMI, but for your Node-RED dashboard you just want a selection of these addresses and they are too scattered to be read all at once, pick a starting address numbered far higher than what you will use for any HMI work and create a new bank of coils or registers just for the Node-RED dashboard.  The PLC can handle this easily and it greatly simplifies the polling for your Node-RED dashboard.  On the Node-RED side of the connection, it’s a good idea to parse and to filter this data as soon as it enters the flow.  Below, the first node creates an appropriate message for each coil, with a topic name and a true/false payload.  This message is then filtered by the “block unless value changes” mode in the filter node and finally a switch (by topic) node separates out each message.  In this example, every Tag coming in from the PLC only triggers downstream nodes when there is a change and each Tag has its own output to connect a wire, and subsequent nodes to.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using a switch node to separate the messages&quot; alt=&quot;Using a switch node to separate the messages&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The filter node blocks redundant data from triggering subsequent nodes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Filter node configuration&quot; alt=&quot;Filter node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-12.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The function node, “modbusMapArray,” creates messages that are much more user-friendly in the Node-RED environment.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Modbus function node&quot; alt=&quot;Modbus function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Quick tip: If your PLC environment has limits on the number of addresses allowed and you want to read a lot of coils, you can work with registers bitwise and stuff 16 coils into one register.&lt;/p&gt;
&lt;h3 id=&quot;reading-data-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#reading-data-types&quot;&gt;Reading Data Types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No matter what data type the PLC is sending over Modbus, it’s going to be sent using the 16-bit registers.  For example, to send 1234.5678 as a 32-bit Float (little-endian), the payload from the PLC will be a seemingly unhelpful array, [21035,17562].  I can simulate this with the &lt;a href=&quot;https://www.automationdirect.com/adc/overview/catalog/software_products/programmable_controller_software/productivity_suite_programming_software&quot;&gt;Productivity Suite Programming Software&lt;/a&gt; from Automation Direct set to simulator mode.  Below, I have created a 32-bit float “Tag,” named “mySampleFloat32,” using modbus registers 40001 and 40002, and set the “Init Value” to 1234.5678.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Productivity Suite Programming Software&quot; alt=&quot;Productivity Suite Programming Software&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-11.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Node-RED is typically used at a much higher level, but luckily there is still a way to work with this low-level data.  Node-RED uses the Buffer Class to work with this type of data stream, but it’s a little tricky.  First the 16-bit registers have to be broken into 8-bit chunks, here we use msg.responseBuffer.buffer to retrieve each octet.  Once our buffer is properly filled, there are many built-in functions to reconstruct the data into the actual number you are looking for.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using msg.responseBuffer.buffer to retrieve each octet&quot; alt=&quot;Using msg.responseBuffer.buffer to retrieve each octet&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-4.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Notice below that to read these 2 registers at 400001 and 400002 I have set my Modbus-Read node to start at “Address” 0 and ready “Quantity” 2 registers.  Unfortunately, there are two different standards for writing Modbus addresses and my PLC uses the traditional convention (400001 to 465536) and this Modbus node uses the hexadecimal convention (4x0000 to 4xFFFF).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Modbus node configuration&quot; alt=&quot;Modbus node configuration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-8.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In this example the byte order from msg.responseBuffer.buffer doesn’t quite match the data type, so we have to rebuild the buffer.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Mapping the data in a function node&quot; alt=&quot;Mapping the data in a function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-13.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Amazingly after all that work we get the response: 1234.5677490234375.  This is the shortcoming of the 32-bit float data type.  Although it can handle a huge range of values, they aren’t very accurate.  For this reason, many times PLCs will send a number as an integer, say 12345678, and the documentation will prescribe 4 decimal place accuracy to bring the number back to 1234.5678.  Find out more ways to work with a Buffer at &lt;a href=&quot;https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html&quot;&gt;https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;general-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#general-architecture&quot;&gt;General Architecture&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although you can off-load some of the higher-level logic from the PLC into Node-RED, it’s important to remember that Node-RED augments, but doesn’t create a replacement for a PLC’s IDE and the IEC 61131-3 suite of languages.  Make a conscious distinction between the type of work the PLC should handle and what you expect from Node-RED.  Any real-time responses to inputs should strictly be handled by the PLC.&lt;/p&gt;
&lt;h3 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#security&quot;&gt;Security&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Connecting Node-RED to your PLC also creates a larger attack surface for cyber threats.  Make sure that you follow the guidelines found on the Node-RED.org site at &lt;a href=&quot;https://nodered.org/docs/user-guide/runtime/securing-node-red&quot;&gt;Securing Node-RED&lt;/a&gt;.  Node-RED’s strength is its ability to make connections where they weren’t possible before, but this can be taken advantage of by a hacker.  For instance, maybe it’s tempting to make Node-RED a transparent gateway and make a RESTful API fully exposing a modbus-flex-write node.  This is amazingly easy and powerful with Node-RED, but anyone who can access your IP could send http://&lt;yourIP&gt;:1880/careful?value=true&amp;amp;fc=15&amp;amp;unitid=1&amp;amp;address=0&amp;amp;quantity=10 and remotely turn on and off whatever they wanted.&lt;/yourIP&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example endpoint flow&quot; alt=&quot;Example endpoint flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-6.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Instead, a better practice would be to more narrowly define what you want to accomplish and only allow Node-RED to do exactly that. In this case you might send http://&lt;yourIP&gt;:1880/honkTheLunchHorn?honk=true&lt;/yourIP&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Locking down the endpoint&quot; alt=&quot;Locking down the endpoint&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/integrating-modbus-with-node-red/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If not done right, there could be some hard lessons, so it’s best to monitor the processes to help track down bugs.  Add a log, keep your eyes out, and as a community let’s work to create stable systems.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Logging failures&quot; alt=&quot;Logging failures&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/integrating-modbus-9.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;How readily upper management gives an “okay” to this new technology comes with how well it is implemented.  There will be some growing pains, but by the end, you will have supercharged your plant, bringing it into the 21st century.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/flowforge-1-7-released/</id>
        <title>FlowFuse 1.7 Now Available with Remote Node-RED Editor Access</title>
        <summary>Further improving fleet management and maintenance of remote Node-RED instances</summary>
        <updated>2023-05-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/flowforge-1-7-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;FlowFuse 1.7 adds new support for accessing the Node-RED Editor on Devices via FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;further-improving-fleet-management-and-maintenance-of-remote-node-red-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#further-improving-fleet-management-and-maintenance-of-remote-node-red-instances&quot;&gt;Further improving fleet management and maintenance of remote Node-RED instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are excited to introduce a new feature that will simplify the process of debugging and developing flows for devices. Our latest feature, &amp;quot;Editing Flows on Devices&amp;quot; allows users to access the editor directly on their device without the need for complex network configurations or firewalls. This feature will significantly improve the user experience, making it easier and more efficient to work with devices.&lt;/p&gt;
&lt;p&gt;This update is a part of our ongoing commitment to making FlowFuse the best possible solution for developing your Node-RED flows, no matter where they&#39;re running. In fact, as part of our last release 1.6, we already introduced the feature: &lt;a href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#access-node-red-logs-from-remote-devices&quot;&gt;&amp;quot;Access Node-RED logs from remote devices&amp;quot;&lt;/a&gt;. This feature made it easy for users to troubleshoot and debug. Building on that, we&#39;ve taken the next step, and it&#39;s now possible to access the Device Editor.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;zS6P3RR86vE&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;device-status-visualisation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#device-status-visualisation&quot;&gt;Device Status Visualisation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This FlowFuse version upgrades device monitoring. It&#39;s made easier to manage your devices effectively, especially when there&#39;s many of them. Now we offer an intuitive, user-friendly method for users to keep an eye on their devices&#39; status and evaluate the health of their team&#39;s devices overall. Creating an overview of your fleet&#39;s health, however large your fleet might be.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;S--viuPhrS8&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;auto-restart-for-hung-node-red-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#auto-restart-for-hung-node-red-instances&quot;&gt;Auto Restart for Hung Node-RED Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This enhancement ensures a more robust and reliable experience when working with Node-RED flows. The launcher now actively monitors the Node-RED process to detect if it has become unresponsive or hung, in addition to the existing checks for start-up and unexpected process exits. This advancement takes us one step further in improving the availability of our Node-RED instances.&lt;/p&gt;
&lt;h2 id=&quot;ongoing-topics&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#ongoing-topics&quot;&gt;Ongoing Topics&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;high-availability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#high-availability&quot;&gt;High Availability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re actively progressing on the topic of enhancing High Availability in FlowFuse for Node-RED. Our initial tasks and modifications have been identified, specifically pertaining to the operation of Node-RED instances within the k8s environment. These adjustments are aimed at constructing a more resilient system. Stay tuned for a comprehensive update regarding our advancements in High Availability.&lt;/p&gt;
&lt;h3 id=&quot;soc2-certification&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#soc2-certification&quot;&gt;SOC2 Certification&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dedicated to upholding the highest levels of security and privacy, our company acknowledges the significance of industry-standard certifications like SOC2 in fostering trust with our customers and partners. We aim to achieve SOC2 Type 1 certification by the end of Q2 and subsequently maintain a continuous SOC2 Type 2 certification. We will keep you informed on our progress as we reach essential milestones in our SOC2 certification journey. Rest assured, our commitment to delivering the utmost security and privacy for our customers and partners remains unwavering.&lt;/p&gt;
&lt;h3 id=&quot;aws-marketplace-onboarding&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#aws-marketplace-onboarding&quot;&gt;AWS Marketplace onboarding&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We are excited to provide an update on our ongoing task of onboarding Node-RED instances to AWS Marketplace via FlowFuse Cloud, which we have started in this Iteration. By offering Node-RED instances through AWS Marketplace, we aim to simplify the deployment process for our customers.&lt;/p&gt;
&lt;p&gt;One of the significant challenges we are currently addressing is handling our current payment system in parallel with a new method. This will ensure a seamless billing experience for our customers, as they will be able to manage their Node-RED instance subscriptions through their existing AWS accounts.&lt;/p&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andreikop&quot;&gt;@andreikop&lt;/a&gt; for their work on the &lt;a href=&quot;https://github.com/FlowFuse/flowforge-driver-k8s/pull/80&quot;&gt;flowforge-driver-k8s #80&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/helm/pull/125&quot;&gt;flowforge/helm #125&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/elenaviter&quot;&gt;@elenaviter&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/helm/pull/126&quot;&gt;flowforge/helm #126&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building. If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re always working to enhance your experience with FlowFuse. Here&#39;s how you can stay informed and contribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roadmap Overview&lt;/strong&gt;: Check out our [Product Roadmap Page/changelog/) to see what we&#39;re planning for future updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entire Roadmap&lt;/strong&gt;: Visit our &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;Roadmap on GitHub&lt;/a&gt; to follow our progress and contribute your ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feedback&lt;/strong&gt;: We&#39;re interested in your thoughts about FlowFuse. Your feedback is crucial to us, and we&#39;d love to hear about your experiences with the new features and improvements. Please share your thoughts, suggestions, or report any &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/new/choose&quot;&gt;issues on GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, we can make FlowFuse better with each release!&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Incorrect number of days displayed when adding a new license &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1895&quot;&gt;#1895&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Users were unable to upgrade modules in Manage Palette, even after restarting Node-RED. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2005&quot;&gt;#2005&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enable &#39;Delete Team&#39; Button &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2031&quot;&gt;#2031&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Triggering a Node-RED restart using the action button resulted in two instances of Node-RED running in the container, causing one instance to crash due to port 1880 being already in use. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1860&quot;&gt;#2031&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Error deleting instance with missing subscription &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2080&quot;&gt;#2080&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Snapshot Rollback no longer working &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2026&quot;&gt;#2026&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Users receiving an unauthorized error when attempting to switch to a team in which they are a member &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1845&quot;&gt;#1845&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cannot select &amp;quot;Member&amp;quot; option when inviting a team member &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/2084&quot;&gt;#2084&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.7.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/flowforge-1-7-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That&#39;s also a great place to send us any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;You can also get help on &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;the Node-RED forums&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As well as in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/discussions&quot;&gt;forum within our Github project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/community-news-05/</id>
        <title>Community News May 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-05-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/community-news-05/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for May 2023, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;ask-me-anything-about-debugging-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#ask-me-anything-about-debugging-node-red&quot;&gt;Ask Me Anything about Debugging Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our monthly Node-RED AMA session will have a special focus on debugging. Nick and Rob will lead us through some useful debug workflows to show how they approach debugging Node-RED applications. During the live coding sessions there will be opportunities for attendees to ask questions in real-time. Join us to learn from the experts on the tips and tricks for debugging Node-RED flows. &lt;a href=&quot;https://flowfuse.com/ask-me-anything/ama-nodered-may/&quot;&gt;Sign-up today to participate&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-with-node-red-dashboard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#getting-started-with-node-red-dashboard&quot;&gt;Getting Started with Node-RED Dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;How can you use Node-RED to create dashboards and interactive graphs of your data? The answer is the Node-RED Dashboard node, the most popular node in the Node-RED community. In this webinar, Rob Marcer will take you through the steps of how to get started with the Node-RED Dashboard. &lt;a href=&quot;https://flowfuse.com/webinars/2023/getting-started-nodered-dashboard/&quot;&gt;Register today&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/&quot;&gt;Chat GPT in Node-RED Function Nodes&lt;/a&gt; - Use Chat GPT to write Node-RED functions directly in the Node-RED interface.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/&quot;&gt;Securing Node-RED&lt;/a&gt; - A look at how you can secure Node-RED deployments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/nodered-community-health/&quot;&gt;Node-RED Community Health&lt;/a&gt; - Some key community metrics for the Node-RED community.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/hannover-messe/&quot;&gt;FlowFuse&#39;s visit to Hannover Messe 2023&lt;/a&gt; - Our CEO and Product Manager visited Hannover Messe in Germany; one of the largest trade shows for manufacturing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/&quot;&gt;FlowFuse 1.6 Now Available&lt;/a&gt; - FlowFuse 1.6 included support for multi-instance Node-RED within a single application as well as support for logging from remote devices.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/&quot;&gt;Node-RED Tips - Subflows, Link Nodes, and the Range Node&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jsonata is a very useful and often underutilised tool built into Node-RED. Steve over at &lt;a href=&quot;https://stevesnoderedguide.com/&quot;&gt;Steve&#39;s Node-RED Guide&lt;/a&gt; has published a great beginners guide. If you are new to Jsonata and want to learn more we recommend you &lt;a href=&quot;https://stevesnoderedguide.com/node-red-and-jsonata-for-beginners&quot;&gt;take a look&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;custom-node-spotlight---node-red-contrib-queue-gate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#custom-node-spotlight---node-red-contrib-queue-gate&quot;&gt;Custom Node Spotlight - node-red-contrib-queue-gate&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-queue-gate&quot;&gt;Queue Gate&lt;/a&gt; is a handy custom node which allows you to control the flow of messages. You might wish to queue up all the messages in a flow and then release them all, once an hour. Maybe you want to release just one message at a time and wait until the prior message completed a section of your flow. Queue Gate makes message queuing really easy without the need to use an external queue solution.&lt;/p&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/community-news-05/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4798023004&quot;&gt;Developer Advocate - Manufacturing &amp;amp; Industrial Automation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4843566004&quot;&gt;Sales Representative&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/</id>
        <title>Chat GPT in Node-RED Function Nodes</title>
        <summary>New Node-RED function with embedded ChatGPT is now open-sourced and available to use!</summary>
        <updated>2023-05-02T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/"/>
        <author><name></name></author>
        <author><name>Steve McLaughlin</name></author>
        <content type="html">&lt;p&gt;Recently we &lt;a href=&quot;https://www.linkedin.com/posts/flowforge_chatgpt-with-node-red-function-nodes-activity-7052725869684953088-2yOA?utm_source=share&amp;amp;utm_medium=member_desktop&quot;&gt;posted a demo of ChatGPT integration in a Node-RED function node&lt;/a&gt;
onto our social media accounts. We have now &lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt&quot; target=&quot;_blank&quot;&gt;open-sourced&lt;/a&gt; this for all to play with, and &lt;strong&gt;welcome any and all contributions&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works---prompt-engineering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/#how-it-works---prompt-engineering&quot;&gt;How it Works - Prompt Engineering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OpenAI make a collection of their &lt;a href=&quot;https://platform.openai.com/docs/models&quot;&gt;Generative AI models&lt;/a&gt; available
via an API. We are wrapping OpenAI&#39;s &lt;a href=&quot;https://www.npmjs.com/package/openai&quot;&gt;node.js module&lt;/a&gt;, and in particular
using the &lt;code&gt;openai.createChatCompletion()&lt;/code&gt; functionality. For this API, you provide a chat history, and ChatGPT will
respond with the next entry in that conversation.&lt;/p&gt;
&lt;p&gt;In order to &amp;quot;train&amp;quot; ChatGPT for our use case of populating Node-RED function nodes, we first tried a collection of prompts, defining specific
requirements for the contents, e.g. &lt;em&gt;&amp;quot;Always write Javascript&amp;quot;&lt;/em&gt;, &lt;em&gt;&amp;quot;Never include the wrapping function definition&amp;quot;&lt;/em&gt;,
&lt;em&gt;&amp;quot;Assume the input is always msg&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It turns out though, that we were over-engineering it, we were not getting reliable results and ended up
realising that ChatGPT&#39;s existing knowledge of Node-RED was sufficient such that we could use that as a prompt:&lt;/p&gt;
&lt;p&gt;Here&#39;s what we settled on:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-18&quot;&gt;
  &lt;pre class=&quot;language-javascript&quot;&gt;&lt;code id=&quot;code-18&quot; class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;system&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;always respond with content for a Node-RED function node, and don&#39;t add any commentary, always use const or let instead of var. Always return msg, unless told otherwise.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; prompt&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-18&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Here we send a &lt;code&gt;system&lt;/code&gt; prompt in order to setup ChatGPT, and then follow that immediately with whatever the user has typed.
From our (limited) testing, this has given us fairly reliable results.&lt;/p&gt;
&lt;p&gt;Breaking this prompt down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;&amp;quot;Always respond with content for a Node-RED function node&amp;quot;&lt;/strong&gt;&lt;/em&gt;: Ensured no surrounding &lt;code&gt;function () {}&lt;/code&gt; definition and set expectations that the function would deal with a &lt;code&gt;msg&lt;/code&gt; and likely &lt;code&gt;msg.payload&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;&amp;quot;Don&#39;t add any commentary&amp;quot;&lt;/strong&gt;&lt;/em&gt;: ChatGPT likes to, well, chat. It would always return raw text justifying decisions, etc. Here, we just wanted the code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;&amp;quot;Always use const or let instead of var&amp;quot;&lt;/strong&gt;&lt;/em&gt;: This was Steve being picky.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;&amp;quot;Always return msg, unless told otherwise&amp;quot;&lt;/strong&gt;&lt;/em&gt;: We found this wasn&#39;t mostly required, but occasionally it would try to return a different variable, and we&#39;d lose context of &lt;code&gt;msg.payload&lt;/code&gt;, or other data stored in &lt;code&gt;msg&lt;/code&gt;. So this just made sure we had the consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The response from this API call is then populated into the contents of the active tab in the function node:&lt;/p&gt;
&lt;img width=&quot;1728&quot; alt=&quot;Screenshot 2023-04-21 at 16 08 47&quot; src=&quot;https://user-images.githubusercontent.com/99246719/233671631-fefa36c1-6db4-4392-a057-314c16fd91b7.png&quot; /&gt;
&lt;p&gt;In order to use it yourself, you will need a &lt;a href=&quot;https://platform.openai.com/account/api-keys&quot;&gt;valid API Key from OpenAI&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;additional-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/#additional-features&quot;&gt;Additional Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was built in about a day by Steve and Joe, and we had plenty of ideas on what we&#39;d like to add to it. We&#39;ve
&lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt&quot;&gt;open-sourced&lt;/a&gt; it, and will add these as issues to the repo, but if anyone want so take a stab at contributing - that&#39;d be most welcome!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Insert at Cursor (&lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt/issues/11&quot;&gt;issue&lt;/a&gt;):&lt;/strong&gt; Currently, the Ask GPT call will replace &lt;em&gt;all&lt;/em&gt; of the content of that tab. Would be great
to have the code insert wherever the cursor last was in order to add to existing code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retain Conversation History (&lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt/issues/12&quot;&gt;issue&lt;/a&gt;):&lt;/strong&gt; Each time a new prompt is provided by the Node-RED user, we send a fresh conversation to OpenAI,
meaning that knowledge of previously asked questions are not retained.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Client side ChatGPT Config (&lt;a href=&quot;https://github.com/FlowFuse/node-red-function-gpt/issues/13&quot;&gt;issue&lt;/a&gt;):&lt;/strong&gt; Currently, when you add a new &amp;quot;function-gpt&amp;quot; node you need to select the ChatGTP
Config node and click &amp;quot;Deploy&amp;quot; before you can ask it a question. Our ChatGPT interaction operates server-side (to
protect your API key), so Node-RED needs that in the runtime first, before a call to ChatGPT can be made. Ideally,
we&#39;d be smarter here and pass client-side creds along with the call such that we can use any changes made by the
user at the time of the call.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flowfuse-assistant---no-api-keys-required!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/chatgpt-nodered-fcn-node/#flowfuse-assistant---no-api-keys-required!&quot;&gt;FlowFuse Assistant - No API Keys Required!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Great news! You no longer need to manage OpenAI API keys or configure ChatGPT nodes. The &lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;FlowFuse Assistant&lt;/a&gt; is now built directly into Node-RED on FlowFuse Cloud, making AI-powered development even easier.&lt;/p&gt;
&lt;p&gt;Available on FlowFuse Cloud, the Assistant offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quick Function Node Creation&lt;/strong&gt;: Add function nodes to your flow without dragging from the palette&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In-line Code Generation&lt;/strong&gt;: Generate JavaScript code for function nodes, JSON for JSON editors, and Vue.js for FlowFuse Dashboard ui-template widgets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flow Explainer&lt;/strong&gt;: Select nodes and click &amp;quot;Explain Flows&amp;quot; to understand what they do&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FlowFuse Assistant helps developers work faster and smarter with Node-RED. &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Start your free trial&lt;/a&gt; to experience AI-powered Node-RED development on FlowFuse Cloud.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/05/device-agent-as-a-service/</id>
        <title>Running the FlowFuse Device Agent as a service on a Raspberry Pi</title>
        <summary>Step by step guide to run the device agent as a service</summary>
        <updated>2023-05-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/05/device-agent-as-a-service/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;FlowFuse&#39;s device agent allows you to manage and run your Node-RED instances on
your own hardware such as a Raspberry Pi. This can be very useful where an
application you&#39;ve written needs to run flows with direct access to hardware sensors.&lt;/p&gt;
&lt;p&gt;In this article I&#39;m going to explain the steps to configure our device agent to run as a service in Raspbian OS,
or any other OS that uses systemd.&lt;/p&gt;
&lt;h2 id=&quot;why-run-the-device-agent-as-a-service%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#why-run-the-device-agent-as-a-service%3F&quot;&gt;Why run the device agent as a service?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The standard process for running FlowFuse&#39;s device agent is to start it on the
command line using the command &lt;code&gt;flowforge-device-agent&lt;/code&gt;. This works fine for testing
but for long-term installations it&#39;s useful to run the device agent as a service.
Once running as a service, the device agent will continue to run even if your
device is restarted or your SSH connection to your Pi fails.&lt;/p&gt;
&lt;h2 id=&quot;set-up-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#set-up-steps&quot;&gt;Set up steps&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;create-the-service-file&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#create-the-service-file&quot;&gt;Create the Service File&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step is creating the systemd unit file for your service. You can start by creating a new file in the
&lt;code&gt;/etc/systemd/system&lt;/code&gt; directory with a .service file extension:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo nano /etc/systemd/system/flowforge-device-agent.service&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;define-the-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#define-the-service&quot;&gt;Define the Service&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the service file, you&#39;ll need to define the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Description&lt;/code&gt;: A brief description of what the service does.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecStart&lt;/code&gt;: The command(s) to execute to start the service.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;User and Group&lt;/code&gt;: The user and group that the service runs as.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type&lt;/code&gt;: Whether the service is a simple or a forking type.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&#39;ve created the content you&#39;ll need for this file and shared it via &lt;a href=&quot;https://github.com/FlowFuse/device-agent/blob/main/service/flowfuse-device.service&quot;&gt;this GitHub page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Copy the code from that page into the nano window you created in step 1, then save and exit out of nano.&lt;/p&gt;
&lt;h3 id=&quot;starting-the-service-on-boot-(optional)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#starting-the-service-on-boot-(optional)&quot;&gt;Starting the service on boot (optional)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want Node-RED to run when the Pi is turned on, or re-booted, you can enable the service to autostart by running the command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl enable flowforge-device-agent.service&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To disable the service, run the command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl disable flowforge-device-agent.service&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;using-your-new-service&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#using-your-new-service&quot;&gt;Using your new service&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can now start your service with the start command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl start flowforge-device-agent&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can check the current status with the status command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl status flowforge-device-agent&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finally, if you need to stop your agent you can do so with the command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl stop flowforge-device-agent&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/05/device-agent-as-a-service/#further-reading&quot;&gt;Further reading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;d like to learn about using services via the systemctl command you can access
the help text by running &lt;code&gt;systemctl -h&lt;/code&gt; from your Pi terminal.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/</id>
        <title>Node-RED Tips - Subflows, Link Nodes, and the Range Node</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-04-20T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-subflows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/#1.-subflows&quot;&gt;1. Subflows&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Subflows are a great way to reuse sections of your flows. Once you have created a subflow, it can easily be dropped into your workspace one or more times.&lt;/p&gt;
&lt;h4 id=&quot;why-use-subflows%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/#why-use-subflows%3F&quot;&gt;Why use subflows?&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Without using a subflow, you can copy and paste a flow into each place you need to use it. This takes up quite a bit of workspace, and makes it harder to update your flow in the future as you&#39;ll have to update each copy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Duplication of the flow&quot; alt=&quot;Duplication of the flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/no-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If we instead put the flow into a subflow we&#39;ll save a lot of workspace and it will be easier to update the reused sections of the flow if we need to in the future.&lt;/p&gt;
&lt;h4 id=&quot;creating-a-subflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/#creating-a-subflow&quot;&gt;Creating a subflow&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You can create a subflow using the burger menu in the top right corner of Node-RED, select Subflows, then Create Subflow. Lay out your subflow, making sure you create an input and output. You can even have more than one output if you want.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Contents of the subflow&quot; alt=&quot;Contents of the subflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can now drop the subflow into your workspace as needed, saving space and making it easier to manage changes to your flow.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using the subflow to reduce duplication of flows&quot; alt=&quot;Using the subflow to reduce duplication of flows&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/using-the-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;2.-link-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/#2.-link-nodes&quot;&gt;2. Link Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Link Nodes allow you to separate your flows into distinct sections. The wires between the link nodes are not visible until you select that part of the flow. You can also link flows on different tabs together.&lt;/p&gt;
&lt;p&gt;Formatting your flows into distinct sections using link nodes can make it easier to read and update your work.&lt;/p&gt;
&lt;p&gt;To use the link node, drag a link in and out node into your flow&#39;s workspace. Now draw a wire as you usually would to link to two nodes together. You should see a link between the nodes but it only shows when you have the link nodes selected.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Linking two link nodes together&quot; alt=&quot;Linking two link nodes together&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/wiring-link-nodes.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In this example below, the first and second flows have the same nodes and functionality. In the second image of the workspace I&#39;ve split the flow into specific groups of nodes.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;A flow without link nodes&quot; alt=&quot;A flow without link nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-without-link-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s easier to read and understand the flow once it&#39;s split up using the link nodes and groups.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The same flow as above, now split up using link nodes&quot; alt=&quot;The same flow as above, now split up using link nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-with-link-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;3.-range-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/3-quick-node-red-tips-6/#3.-range-node&quot;&gt;3. Range Node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes you might need to map one numbering scale onto another. For example, where a user has selected a value between 0 and 10 but you want to use and store their response as a percentage. The Range node makes this task very easy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example of using the range node&quot; alt=&quot;Example of using the range node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flow-using-range.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To configure the node, set it up as follows:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Configuration of the range node&quot; alt=&quot;Configuration of the range node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/range-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You should now see that the input values are translated to the appropriate value out of 100.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The range note in use&quot; alt=&quot;The range note in use&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/range-demo.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;. You can also read some of our previous Node-RED tips using the links below.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/&quot;&gt;Node-RED Tips - Importing, Exporting, and Grouping Flows&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/&quot;&gt;Node-RED Tips - Smooth, Catch, and Maths&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/&quot;&gt;Node-RED Tips - Exec, Filter, and Debug&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/&quot;&gt;Node-RED Tips - Deploying, Debugging, and Delaying&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/&quot;&gt;Node-RED Tips - Wiring Shortcuts&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/hannover-messe/</id>
        <title>FlowFuse&#39;s visit to Hannover Messe 2023</title>
        <summary>A recap of FlowFuse&#39;s visit to Hannover Messe</summary>
        <updated>2023-04-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/hannover-messe/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;&amp;quot;Do you use Node-RED?&amp;quot; This simple question became our favorite conversation opener as ZJ and I attended Hannover Messe, the world&#39;s leading industrial trade fair.&lt;/p&gt;
&lt;p&gt;To our delight, the answer was almost always &amp;quot;Yes.&amp;quot; This allowed us to dive into truly fruitful discussions with Node-RED experts, exploring the latest industry trends, connecting with potential partners, and sharing our vision for the future of Node-RED in the manufacturing sector. During our visit, we had the pleasure of engaging with several vendors, including Bosch Rexroth, Siemens, Wago, Weidmüller, RevolutionPi, and more. It was genuinely inspiring to see the widespread adoption and usage of Node-RED across the entire industry. See also our &lt;a href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#the-standard-for-edge-computing-and-plcs&quot;&gt;arcticle&lt;/a&gt; about the adoption of Node-RED for PLCs and Gateways.&lt;/p&gt;
&lt;p&gt;FlowFuse&#39;s innovative solutions, such as remote deployment of Node-RED instances, seamless updates, effortless rollbacks, and built-in security, are already addressing many challenges faced by Node-RED users in the industry today. The positive feedback we received at Hannover Messe has bolstered our commitment to making Node-RED more accessible and production-ready for industrial and enterprise scenarios. As we forge ahead, we are eager to collaborate with more partners, learn from industry leaders, and remain at the forefront of Node-RED development. Together, we can build a more connected, efficient, and innovative manufacturing industry. With each new booth we visited and every conversation we had, it became increasingly clear that Node-RED and FlowFuse are well on their way to becoming an integral part of the industrial landscape.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/nodered-community-health/</id>
        <title>Node-RED Community Health</title>
        <summary>Node-RED community metrics</summary>
        <updated>2023-04-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/nodered-community-health/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;It is often a challenge to measure the health of an open source project, like Node-RED. Individuals can download and use Node-RED without any indication or feedback to their ongoing satisfaction or usage. However, it is still interesting to look at a variety of metrics to understand the size of the Node-RED community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitHub Stars&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A popular method for demonstrating popularity of an open source project are GitHub stars. Node-RED has over 16K stars and when &lt;a href=&quot;https://synodus.com/blog/low-code/open-source-low-code-platforms/&quot;&gt;compared to other low-code platforms&lt;/a&gt; on GitHub has a strong showing. FWIW, GitHub stars are open to gaming so it is not a great long-term indicator of community health and engagement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node-RED Library&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the core of the Node-RED community is the library of nodes and flows that have been developed by community members. The current library has over &lt;a href=&quot;https://flows.nodered.org/search?type=node&amp;amp;sort=downloads&quot;&gt;4300 nodes available&lt;/a&gt;, some of the more popular nodes are downloaded more than 10K times per week. The large library of community nodes supports a wide range of protocols, data sources, data stores, and much more. This makes Node-RED more relevant and useful to many more potential users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node-RED Website Traffic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the last year, Node-RED has had over 1.9 million unique visitors to the &lt;a href=&quot;https://nodered.org/&quot;&gt;nodered.org&lt;/a&gt; website, over 160K on a monthly basis. The most popular pages, after the home page, are the getting started pages. This demonstrates a strong interest in learning more about how to use Node-RED.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NPM Downloads &amp;amp; Docker Pull Requests&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Node-RED is installed by lots of people using Docker and NPM. The project averages over 500K/month pull requests from &lt;a href=&quot;https://hub.docker.com/r/nodered/node-red&quot;&gt;Docker Hub&lt;/a&gt; and 100K/month pull requests on &lt;a href=&quot;https://npm-stat.com/charts.html?package=node-red&amp;amp;from=2017-03-22&amp;amp;to=2023-03-22&quot;&gt;NPM&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node-RED Forums&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;Node-RED community forum&lt;/a&gt; is the go to place to get community support. It is a very popular community with over 900K page views per month. The amazing thing is that a very large percentage of questions receive replies from other community members. A great sign of a healthy community.&lt;/p&gt;
&lt;p&gt;Overall, the Node-RED community is large, healthy and engaged.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/flowforge-1-6-released/</id>
        <title>FlowFuse v1.6 Now Available</title>
        <summary>FlowFuse Now Supports Multi-Instance Node-RED for Complex Application Development</summary>
        <updated>2023-04-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/flowforge-1-6-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The new FlowFuse 1.6 adds new support for multi-instance Node-RED within a single application and support for logging from remote devices.&lt;/p&gt;
&lt;h2 id=&quot;flowfuse-applications-can-now-support-multi-instance-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#flowfuse-applications-can-now-support-multi-instance-node-red&quot;&gt;FlowFuse Applications Can Now Support Multi-Instance Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse 1.6 expands the scope of applications to now allow for multiple instances of Node-RED. For complex Node-RED applications, it is common to have different flows interacting with other flows or flows deployed to different target environments. The ability to associate all these different flows with a single application makes it easier for the development, test and deployment of these types of complex applications.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;OHChdWeRI9Q&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;access-node-red-logs-from-remote-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#access-node-red-logs-from-remote-devices&quot;&gt;Access Node-RED logs from remote devices&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse makes it easy to deploy Node-RED out to remote devices. However, once Node-RED has been deployed to the remote device it is often difficult to troubleshoot or debug. Now with FlowFuse 1.6, you can get access to the Node-RED logs from remote devices. This makes it much easier to understand and debug the behavior of a remote device.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;yW1zxwiCmto&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#other-improvements&quot;&gt;Other Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Update email address verification  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/813&quot;&gt;#813&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Reminder email about trial doesn&#39;t include a link to FF Cloud &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1815&quot;&gt;#1815&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sign-up coupons improvement &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1788&quot;&gt;#1788&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;New FF_Instance_* envvars inline with new terminology &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1844&quot;&gt;#1844&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deprecate FF_PROJECT_* envvars &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1844&quot;&gt;#1844&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Integrate with PostHog events &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/1922&quot;&gt;#1922&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Introduce search bar to docs/handbook  &lt;a href=&quot;https://github.com/FlowFuse/website/pull/620&quot;&gt;#620&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Deleting instances from the instance list fails &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1859&quot;&gt;#1859&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Removing old projects with missing subscriptions fails &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1837&quot;&gt;#1837&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Changing to a team as a member shows unauthorized error &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1845&quot;&gt;#1845&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Application Overview: “Open Editor” shouldn’t show (or should be disabled) if in “Starting” state &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1931&quot;&gt;#1931&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.6.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/flowforge-1-6-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That&#39;s also a great place to send us any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;You can also get help on &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;the Node-RED forums&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As well as in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/discussions&quot;&gt;forum within our Github project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/securing-node-red-in-production/</id>
        <title>Securing Node-RED</title>
        <summary>Step-by-step guide for securing your Node-RED projects.</summary>
        <updated>2023-04-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/securing-node-red-in-production/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Node-RED is very easy to get up and running. Whether you run it locally, in Docker, on a Raspberry Pi, or on a service such as FlowFuse Cloud you can have a project up and running in minutes.&lt;/p&gt;
&lt;p&gt;One thing that can get overlooked is the security of Node-RED. From personal experience, the first few times I installed Node-RED I was more focussed on the possibilities of what I could do with this new tool than I was keeping my projects secure.&lt;/p&gt;
&lt;p&gt;In this article I’m going to look at some easy ways to make your Node-RED project more secure, even when first learning about it in a hobby environment.&lt;/p&gt;
&lt;h2 id=&quot;protecting-access-from-your-lan-to-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/#protecting-access-from-your-lan-to-node-red&quot;&gt;Protecting access from your LAN to Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you have an instance of Node-RED running it can usually be accessed from anywhere on your LAN (local area network) by pointing a web browser to the relevant IP address and port.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://192.168.0.3:1880&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;With a URL similar to the one above, depending on your specific network and Node-RED configuration, anyone on your LAN can view but more importantly edit your flows. This can be really useful when you are first learning about Node-RED but it’s always a good idea to get into the habit of locking down access to the editor, even if you trust everyone who can access your LAN.&lt;/p&gt;
&lt;p&gt;One of the easiest ways to protect your flows is to add a username and password to your Node-RED instance.&lt;/p&gt;
&lt;p&gt;The first step is to find your Node-RED settings.js file. It&#39;s not always in the same place but on a default Debian Linux installation it can be found in this directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd ~/.node-red&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you list that directory you should now see something like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Where your settings.js should show&quot; alt=&quot;Where your settings file should show&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ls.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We now need to edit settings.js, I&#39;m going to use my favourite text editor, &lt;a href=&quot;https://www.nano-editor.org/&quot;&gt;Nano&lt;/a&gt; to do that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nano settings.js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We now need to find and edit the following section of the settings file:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The settings file before being edited&quot; alt=&quot;The settings file before being edited&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/without-password.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;For this example, I&#39;m going to add a password and uncomment the relevant section of the settings file, you could also change the username for additional security.&lt;/p&gt;
&lt;p&gt;To create the password we&#39;ll need to use a command line tool which is included in Node-RED. Open a second terminal then run this command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node-red admin hash-pw&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Put in your new password, I&#39;ll use the password &#39;flowforge&#39; in this example. The tool returns your password in a hashed format:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The Node-RED tool outputs the hashed password&quot; alt=&quot;The Node-RED tool outputs the hashed password&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/password.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We can now return to the other terminal window, uncomment the section then paste in the new password, this is how it looks for me:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The settings file with the relevant section uncommented and the password set&quot; alt=&quot;The settings file with the relevant section uncommented and the password set&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/with-password.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We can now save and exit out of the settings file.&lt;/p&gt;
&lt;p&gt;The last step is to restart Node-RED, I&#39;m using Debian so the command is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node-red-restart&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now, when we try to access Node-RED I will need to provide a username and password.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using the username and password to login to Node-RED&quot; alt=&quot;Using the username and password to login to Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/login.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You might also want to consider turning off the editor interface once you are happy with your flows. This can make it a little harder to make changes to your project but it also gives you peace of mind that nobody has accidentally or deliberately changed your flows. You can turn off the editor interface as follows.&lt;/p&gt;
&lt;p&gt;Edit your settings.js file as explained above, look for the following section:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The setting file before turning off the editor&quot; alt=&quot;The setting file before turning off the editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/editor-on.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;All you need to do is uncomment the bottom line then change the value from false to true, once done it should look something like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The setting file after turning off the editor&quot; alt=&quot;The setting file after turning off the editor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/editor-off.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Now restart Node-RED as covered above, then try accessing your Node-RED instance again. You will no longer be able to edit or view your flows.&lt;/p&gt;
&lt;p&gt;Using these two features, we now have much better control over who can access the design interface for Node-RED.&lt;/p&gt;
&lt;h2 id=&quot;traffic-to-your-node-red-instance-is-unencrypted&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/#traffic-to-your-node-red-instance-is-unencrypted&quot;&gt;Traffic to your Node-RED instance is unencrypted&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hopefully, we all know the importance of encrypting your connections between devices to stop people intercepting your traffic. This isn&#39;t a huge concern when working on your home LAN but what if you want to access your Node-RED instance from a remote location?&lt;/p&gt;
&lt;p&gt;There are two obvious options, HTTPS, and a VPN (Virtual Private Network).&lt;/p&gt;
&lt;p&gt;We could setup your Node-RED traffic to run over HTTPS, this solution ensures that all traffic to and from your Node-RED is encrypted. The downside to this approach is it&#39;s quite complex to set up. We will need to have a domain name, open up ports on our LAN&#39;s firewall, use a HTTPS certificate provider and then make sure we remember to renew the certificates as needed. It&#39;s doable if you are comfortable with those concepts (I covered how to do this as part of my blog &lt;a href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/&quot;&gt;hosting FlowFuse on Google Cloud&lt;/a&gt;) but there is an easier way to get started, using a VPN.&lt;/p&gt;
&lt;p&gt;A VPN provides a lot of security advantages depending on which you are using and how it is configured. To secure my traffic I&#39;m going to use a great service call &lt;a href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt; which is free for personal projects.&lt;/p&gt;
&lt;p&gt;I&#39;m going to install Tailscale on the Raspberry Pi I&#39;m running Node-RED on as well as any other devices I want to access my project from. Once that&#39;s done I can access Node-RED from anywhere with internet access but more importantly the traffic to and from my devices is also encrypted.&lt;/p&gt;
&lt;p&gt;Before we start, it&#39;s important to remember that a VPN is only as secure as the company who runs it. You should always consider if you trust the VPN provider as they could potentially access your devices. I trust Tailscale but please do your own research before using a VPN provider.&lt;/p&gt;
&lt;p&gt;The first step we need to take is creating a Tailscale account, &lt;a href=&quot;https://login.tailscale.com/start&quot;&gt;you can sign up for free here&lt;/a&gt;. We next need to add our devices to our VPN using their software, I&#39;m installing Tailscale on my Apple laptop, Google phone as well as the Raspberry Pi I&#39;m running Node-RED on.&lt;/p&gt;
&lt;p&gt;The install process is really easy, even on the Pi running Raspbian the steps you need to take are well explained in the &lt;a href=&quot;https://tailscale.com/download/linux/debian-bullseye&quot;&gt;Tailscale docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the Pi, these are the commands we need to run.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add Tailscale to the Apt package manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg &amp;gt;/dev/null&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl -fsSL https://pkgs.tailscale.com/stable/debian/bullseye.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get update&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Install Tailscale&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get install tailscale&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Start Tailscale and connect your device&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;sudo tailscale up&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After running the last command, we need to follow the on screen prompts to link our devices to your VPN.&lt;/p&gt;
&lt;p&gt;One last thing which you might want to consider doing, every few months you will need to reconnect your devices to your VPN, if you are only going to be accessing your Node-RED device over the VPN you should consider &lt;a href=&quot;https://tailscale.com/kb/1028/key-expiry/&quot;&gt;disabling your Tailscale key expiry&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OK, now we&#39;ve got our devices all connected you should see something like this in the Tailscale dashboard.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Tailscale dashboard showing my three devices&quot; alt=&quot;Tailscale dashboard showing my three devices&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/tailscale.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;I can now access Node-RED on my Pi from my laptop and phone by pointing a browser to the correct IP address (as shown in the image above) with the port for Node-RED:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://100.71.28.60:1880&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I’ve now secured all traffic between my devices and Node-RED project, I can access Node-RED from anywhere on the internet.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Accessing Node-RED via the VPN&quot; alt=&quot;Accessing Node-RED via the VPN&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr-via-vpn.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you follow these steps you should be on the right path to running a more secure Node-RED instance. There is a lot more you can do and I recommend you read the &lt;a href=&quot;https://nodered.org/docs/user-guide/runtime/securing-node-red&quot;&gt;relevant docs on the Node-RED&lt;/a&gt; website to gain some more ideas.&lt;/p&gt;
&lt;h2 id=&quot;what-about-hosting-node-red-on-a-cloud-solution-such-as-flowfuse%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/#what-about-hosting-node-red-on-a-cloud-solution-such-as-flowfuse%3F&quot;&gt;What about hosting Node-RED on a cloud solution such as FlowFuse?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this article, I&#39;ve focussed on hosting Node-RED on a Pi on your own LAN but if you use FlowFuse Cloud to host Node-RED the solutions discussed above are either ready out of the box or are not needed.&lt;/p&gt;
&lt;p&gt;By default, the Node-RED editor is secured using your FlowFuse user credentials. You can also enable SSO to enhance account security and easily grant access to team members. With role-based access control, you can further protect your flows by managing who can view or edit them.&lt;/p&gt;
&lt;p&gt;All traffic to FlowFuse and your Node-RED instances is protected by HTTPS. FlowFuse has set up the domain name and manages the certificates, so you can spend time on your flows rather than configuring security. Additionally, remote device access is secured through encrypted tunnels, providing comprehensive protection for your deployments.&lt;/p&gt;
&lt;p&gt;FlowFuse has a &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; if you&#39;d like to see how we&#39;ve made secure hosting of Node-RED easy.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/securing-node-red-in-production/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;How ever you host Node-RED, it&#39;s a great idea to get into good security practices as early as possible to ensure that no unsecured Node-RED instances are exposed to the internet. I hope some of the tips above help you get started down the path to creating more secure Node-RED projects.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/04/community-news-04/</id>
        <title>Community News April 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-04-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/04/community-news-04/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for April 2023, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;node-red-ask-me-anything&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#node-red-ask-me-anything&quot;&gt;Node-RED Ask Me Anything&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back by popular demand, FlowFuse is hosting a monthly Node-RED Ask Me Anything session on April 13th. This is a great opportunity to ask Nick O’Leary, co-creator of Node-RED &amp;amp; FlowFuse CTO, and Rob Marcer, Node-RED FlowFuse Developer Educator your questions about Node-RED. &lt;a href=&quot;https://flowfuse.com/ask-me-anything/ama-nodered-april/&quot;&gt;Sign-up today to participate&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;connect%2C-integrate%2C-visual-industrial-production-metrics-with-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#connect%2C-integrate%2C-visual-industrial-production-metrics-with-node-red&quot;&gt;Connect, Integrate, Visual Industrial Production Metrics with Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Join Steve McLaughlin from FlowFuse as he showcases how easy it is to use Node-RED to visualize popular production metrics using Node-RED. &lt;a href=&quot;https://flowfuse.com/webinars/2023/industrial-data-node-red/&quot;&gt;Register today&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/&quot;&gt;Comparing Node-RED Dashboards Solutions&lt;/a&gt; - A popular article comparing Node-RED Dashboard, uibuilder and FlexDash.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/&quot;&gt;IBM Cloud removes Node-RED starter application&lt;/a&gt; - IBM has discontinued their Node-RED Starter Application, discover how to migrate to FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/&quot;&gt;The benefits and drawbacks of using Node-RED function nodes&lt;/a&gt; - Node-RED function nodes provide a great deal of flexibility in Node-RED. Discover the benefits and drawbacks of using them.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/&quot;&gt;FlowFuse 15. Now Available&lt;/a&gt; - FlowFuse 1.5 included updates to the UI and architecture to allow for future features.&lt;/p&gt;
&lt;p&gt;Node-RED Quick Tips - Rob Marcer, FlowFuse Developer Educator has a weekly series of Node-RED hints and tips&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/&quot;&gt;Node-RED Tips - Importing, Exporting, and Grouping Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/&quot;&gt;Node-RED Tips - Smooth, Catch, and Math&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;quantum-for-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#quantum-for-node-red&quot;&gt;Quantum for Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Discover how you can incorporate &lt;a href=&quot;https://theailaboratory.wordpress.com/2023/03/24/quantum-for-everyone/&quot;&gt;quantum technologies&lt;/a&gt; into your Node-RED flows.&lt;/p&gt;
&lt;h3 id=&quot;image-recognition-within-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#image-recognition-within-node-red&quot;&gt;Image recognition within Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kazuhito Yokoi, a researcher at Hitachi, has published an &lt;a href=&quot;https://kazuhitoyokoi.medium.com/sharing-node-red-flow-of-image-recognition-application-on-github-4d667cdea9f7&quot;&gt;interesting article&lt;/a&gt; detailing how to incorporate TensorFlow into a Node-RED application to do image recognition.&lt;/p&gt;
&lt;h3 id=&quot;custom-node-spotlight---node-red-contrib-web-worldmap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#custom-node-spotlight---node-red-contrib-web-worldmap&quot;&gt;Custom Node Spotlight - node-red-contrib-web-worldmap&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you would like to include a map in your next project Worldmap is a really good place to start. You can pass coordinates in to set the map to a location or you can use the built in search tool to find a location. As a user manipulates the map a stream of updated coordinates can be passed back to your flows to trigger additional actions. It&#39;s a really useful tool, take a &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-web-worldmap&quot;&gt;look here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/04/community-news-04/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. Check out the current openings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4798023004&quot;&gt;Developer Advocate - Manufacturing &amp;amp; Industrial Automation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/</id>
        <title>IBM Cloud removes Node-RED starter application</title>
        <summary>Get up and running with a Starter Application for Node-RED with FlowFuse or migrate your existing flows from IBM Cloud</summary>
        <updated>2023-03-29T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;IBM Cloud has &lt;a href=&quot;https://www.ibm.com/cloud/blog/announcements/deprecation-of-ibm-cloud-starter-kits&quot;&gt;recently announced&lt;/a&gt; that they will no longer be providing their Cloud App Service Starter Kits, including the &lt;a href=&quot;https://developer.ibm.com/tutorials/how-to-create-a-node-red-starter-application/&quot;&gt;Node-RED Starter Application&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;node-red-starter-application&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#node-red-starter-application&quot;&gt;Node-RED Starter Application&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re looking for an alternative place to get started with Node-RED then FlowFuse, founded by Node-RED co-creator Nick O&#39;Leary, are here to help you with Cloud-hosted Node-RED as well as infrastructure and tooling to scale your Node-RED instances in production.&lt;/p&gt;
&lt;p&gt;As an ex-IBM Employee myself, over the years, I&#39;ve been very dependant upon the Node-RED Starter Application in IBM Cloud. I&#39;d used it dozens of times with clients to showcase the value of Node-RED and how easy it is to spin up integrations between hardware devices, APIs and online services.&lt;/p&gt;
&lt;p&gt;If you&#39;re now looking for somewhere to rely on in order to easily spin up new instance of Node-RED, then FlowFuse is the obvious answer. If you&#39;re completely new for Node-RED too, we can also help you there with our &lt;a href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/&quot;&gt;Getting Started&lt;/a&gt; guide.&lt;/p&gt;
&lt;p&gt;You can sign up for a &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free FlowFuse Cloud Account&lt;/a&gt; where you&#39;ll be given one small Node-RED instance for free, for your first month.&lt;/p&gt;
&lt;h2 id=&quot;integrations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#integrations&quot;&gt;Integrations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;ve seen the excellent &lt;a href=&quot;https://developer.ibm.com/tutorials/how-to-create-a-node-red-starter-application/&quot;&gt;&amp;quot;Create a Node-RED starter application&amp;quot;&lt;/a&gt; article on IBM Developer, you&#39;ll probably be looking to connect up to a Cloudant Instance, or other IBM Cloud Services. Don&#39;t worry. All of that is still available through Node-RED on FlowFuse.&lt;/p&gt;
&lt;p&gt;You can install the relevant nodes in one of two places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Node-RED Palette Manager:&lt;/strong&gt; Click &amp;quot;Menu &amp;gt; Manage Palette &amp;gt; Install&amp;quot;. The menu is available via the icon in the top-right of your running Node-RED Instance)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of Node-RED&#39;s Manage Palette menu&quot; alt=&quot;Screenshot of Node-RED&#39;s Manage Palette menu&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/nr-manage-palette-cloudant.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Instance Settings:&lt;/strong&gt; For a given Instance in FlowFuse, click &amp;quot;Settings &amp;gt; Palette&amp;quot;. You can then define the npm module name and versions explicitely in the &amp;quot;Installed Modules&amp;quot; section&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot of FlowFuse&#39;s &#39;Installed Modules&#39; option in Instance &gt; Settings &gt; Palette&quot; alt=&quot;Screenshot of FlowFuse&#39;s &amp;quot;Installed Modules&amp;quot; option in Instance &gt; Settings &gt; Palette&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-installed-modules.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s also easy to setup &lt;a href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/&quot;&gt;Environment Variables&lt;/a&gt; for Node-RED in FlowFuse for when you integrate with external services like APIs too.&lt;/p&gt;
&lt;h2 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As with IBM Cloud, FlowFuse makes it very easy to secure your Node-RED Applications. &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/#security&quot;&gt;FlowFuse offers three tiers of security&lt;/a&gt; options on your Node-RED Instances to secure any exposed HTTP routes on your Node-RED instance, e.g. REST API endpoints or Node-RED Dashboard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;None&lt;/strong&gt;: Anyone will be able to access the exposed routes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Basic Auth&lt;/strong&gt;: Setup a single, dedicated username and password combination that is required in order to access the routes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlowFuse Credentials&lt;/strong&gt;: Visitors can use their FlowFuse username/password in order to access the endpoints. This also includes SSO if you have that configured for your FlowFoerge Team.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;migrating-existing-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#migrating-existing-instances&quot;&gt;Migrating Existing Instances&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re looking to move your Node-RED applications from IBM Cloud, then you can do so through one of two options:&lt;/p&gt;
&lt;h3 id=&quot;node-red-tools-plugin&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#node-red-tools-plugin&quot;&gt;Node-RED Tools Plugin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can use our Node-RED Tools plugin to migrate your flows and credentials over to FlowFuse. You can read the details in our &lt;a href=&quot;https://flowfuse.com/docs/migration/introduction/&quot;&gt;Migration Guide&lt;/a&gt;, which also includes instructions on how to export your environment variables too.&lt;/p&gt;
&lt;h3 id=&quot;manual-import&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/ibmcloud-starter-removed/#manual-import&quot;&gt;Manual Import&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This will only enable you to import your Flows, not the associated credentials.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Export your existing &lt;code&gt;flows.json&lt;/code&gt; from your IBM Cloud-hosted Node-RED instance by choosing &amp;quot;Export &amp;gt; All Flows &amp;gt; Download&amp;quot; within Node-RED&lt;/li&gt;
&lt;li&gt;Create a new Application on FlowFuse&lt;/li&gt;
&lt;li&gt;Once created, click the Node-RED instance that has been generated within your Application&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Settings&amp;quot;&lt;/li&gt;
&lt;li&gt;Scroll down and select the &amp;quot;Import Instance&amp;quot; option&lt;/li&gt;
&lt;li&gt;Choose your &lt;code&gt;flows.json&lt;/code&gt; file that you downloaded earlier.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;If you have any questions about the above, or more generally about Node-RED or FlowFuse, then please do reach out and &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;get in touch&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/</id>
        <title>Node-RED Tips - Importing, Exporting, and Grouping Flows</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-03-27T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-copy-and-share-your-flows-using-export-and-import&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#1.-copy-and-share-your-flows-using-export-and-import&quot;&gt;1. Copy and share your flows using Export and Import&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED provides both import and export features that allow you to save your flows and settings as compressed JSON files. You can use these features to easily move your flows between multiple Node-RED instances or to back up your work.&lt;/p&gt;
&lt;p&gt;To import a flow, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the three horizontal lines in the upper right corner of the Node-RED editor and click on &amp;quot;Import&amp;quot;.&lt;/li&gt;
&lt;li&gt;Select the JSON file that contains the flow you want to import.&lt;/li&gt;
&lt;li&gt;Click on &amp;quot;Import&amp;quot; and the flow will be imported into the current instance of Node-RED.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To export a flow, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on the three horizontal lines in the upper right corner of the Node-RED editor and click on &amp;quot;Export&amp;quot;.&lt;/li&gt;
&lt;li&gt;Select the type of export you want to perform - this can be either the &amp;quot;Clipboard&amp;quot; or &amp;quot;File&amp;quot;.&lt;/li&gt;
&lt;li&gt;If you chose &amp;quot;File&amp;quot; you will be prompted to save a compressed JSON file to your computer; if you chose &amp;quot;Clipboard&amp;quot; the flow JSON will be copied to your clipboard.&lt;/li&gt;
&lt;li&gt;Use the exported file or clipboard content to import into a different instance of Node-RED.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Importing and exporting your flows&quot; alt=&quot;Importing and exporting your flows&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/import-export.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Keep in mind that some nodes or flows may require additional setup or node installation on the Node-RED instance you import your flow to.&lt;/p&gt;
&lt;h3 id=&quot;2.-import-helpful-example-flows-provided-with-custom-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#2.-import-helpful-example-flows-provided-with-custom-nodes&quot;&gt;2. Import helpful example flows provided with custom nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Node-RED, custom nodes can include examples that provide users with a starting point for using the node. These examples can help users understand how a node works and how it can be integrated into their flows.&lt;/p&gt;
&lt;p&gt;To use example flows in custom nodes, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Node-RED editor and drag the custom node you want to use into your flow.&lt;/li&gt;
&lt;li&gt;Double-click on the node to open its configuration panel.&lt;/li&gt;
&lt;li&gt;Look for an &amp;quot;Examples&amp;quot; menu or button within the node configuration panel. The name and location of the Examples button can vary depending on the node.&lt;/li&gt;
&lt;li&gt;Click on the &amp;quot;Examples&amp;quot; button to bring up a list of example flows included with the node.&lt;/li&gt;
&lt;li&gt;Select the example flow you want to use and click on &amp;quot;Import&amp;quot; to add the example flow to your Node-RED workspace.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the example flow has been added to your workspace, you can modify it to fit your specific needs.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using the example flow included in the moment node&quot; alt=&quot;Using the example flow included in the moment node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s important to note that while custom node examples can be a useful starting point, they may not always work seamlessly with your other flows or nodes. Be sure to thoroughly test any custom node examples before incorporating them into a production environment.&lt;/p&gt;
&lt;h3 id=&quot;3.-group-nodes-together-to-make-your-flows-easier-to-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#3.-group-nodes-together-to-make-your-flows-easier-to-read&quot;&gt;3. Group nodes together to make your flows easier to read&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The group feature in Node-RED allows users to visually group nodes together within the workspace. This feature offers several benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Improved organization: The group feature allows you to group related nodes visually, which can make your flow easier to understand and navigate. This can be particularly helpful for larger, more complex flows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Simplified editing: When you group nodes together, you can edit or move them as a single unit, rather than individually. This can save time and reduce the chance of errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easier sharing: When you share your flow with others, the group feature allows you to package related nodes together, making it easier for others to understand and use your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reduced clutter: Grouping nodes can help reduce the visual clutter in your workspace, making it easier to focus on key aspects of your flow.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Grouping your nodes to make them easier to read&quot; alt=&quot;Grouping your nodes to make them easier to read&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/groups.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Overall, the group feature in Node-RED is a valuable tool that can help users better organise, edit, and share their flows.&lt;/p&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can read our previous Node-RED tips here.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/&quot;&gt;Node-RED Tips - Smooth, Catch, and Math&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/&quot;&gt;Node-RED Tips - Exec, Filter, and Debug&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/&quot;&gt;Node-RED Tips - Deploying, Debugging, and Delaying&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/&quot;&gt;Node-RED Tips - Wiring Shortcuts
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;version-control-and-collaboration-for-your-node-red-flows&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-5/#version-control-and-collaboration-for-your-node-red-flows&quot;&gt;Version Control and Collaboration for Your Node-RED Flows&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; simplifies managing and collaborating on your Node-RED flows with seamless version control. You can easily track changes, take snapshots, and revert to previous versions, ensuring your work is always safe and recoverable.&lt;/p&gt;
&lt;p&gt;With FlowFuse &lt;a href=&quot;https://flowfuse.com/docs/user/shared-library/#shared-team-library&quot;&gt;Team Library&lt;/a&gt;, sharing flows across different Node-RED instances is effortless. This Library feature allows you to organize and share flows among team members without the need for manual copying, making collaboration more efficient and effective.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; for a free trial today and discover how FlowFuse can enhance your Node&lt;/strong&gt;*&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/</id>
        <title>The benefits and drawbacks of using Node-RED function nodes</title>
        <summary>In this blog post, I will discuss some of the benefits and drawbacks of using Function nodes in your next Node-RED project.</summary>
        <updated>2023-03-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Function nodes are an essential part of Node-RED. They allow you to write custom JavaScript functions that can be used in your Node-RED flows. In this blog post, I will discuss some of the benefits and drawbacks of using Function nodes in your next project.&lt;/p&gt;
&lt;h2 id=&quot;5-benefits-of-using-function-nodes%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/#5-benefits-of-using-function-nodes%3A&quot;&gt;5 Benefits of using Function Nodes:&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example showing how to use the function node&quot; alt=&quot;Example showing how to use the function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/function-example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Customisation:&lt;/strong&gt; Function nodes allow you to write custom JavaScript functions that can be tailored to your specific needs. You can create complex functions that perform a variety of tasks, the only limit is your programming skills.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; Function nodes can be reused in multiple flows, saving you time and effort. You can create a library of custom functions that can be easily accessed and reused in different flows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Debugging:&lt;/strong&gt; Function nodes provide an easy way to debug your code. You can use console.log statements to output debug information to the Node-RED debug panel, making it easier to identify and fix issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Function nodes can be more performant than using multiple nodes to achieve the same result. By combining multiple tasks into a single function, you can improve performance, assuming your code is efficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flexibility:&lt;/strong&gt; Function nodes provide a high degree of flexibility. You can use them to perform tasks that are not possible using a single, standard Node-RED node, such as complex data manipulation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;5-benefits-of-avoiding-function-nodes%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/#5-benefits-of-avoiding-function-nodes%3A&quot;&gt;5 Benefits of avoiding Function Nodes:&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example showing how to not use the function node&quot; alt=&quot;Example showing how to not use the function node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/no-function-example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; Not using function nodes can make your flows simpler and easier to understand. By using standard Node-RED nodes, you can create flows that are easy to follow and maintain for both you and your team.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ease of Use:&lt;/strong&gt; Standard Node-RED nodes are easy to use and require no programming knowledge. This makes it easier for non-technical users to create and maintain flows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modularity:&lt;/strong&gt; By using standard Node-RED nodes, you can create modular flows that can be easily modified and extended. This makes it easier to add new functionality to your flows as your needs change.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community Support:&lt;/strong&gt; Standard Node-RED nodes have a large and active community, providing support and resources for users. This can make it easier to find solutions to common problems and share knowledge with others.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compatibility:&lt;/strong&gt; Standard Node-RED nodes are usually compatible with all versions of Node-RED, making it easier to migrate flows between different environments.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;how-to-easily-create-function-nodes-in-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/#how-to-easily-create-function-nodes-in-flowfuse&quot;&gt;How to Easily Create Function Nodes in FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse offers a robust platform for building, scaling, and securing your Node-RED applications.&lt;/p&gt;
&lt;p&gt;We are constantly adding new features to make it easy to use in the enterprise where you can rapidly improve your industrial processes. The &lt;strong&gt;&amp;quot;FlowFuse Assistant.&amp;quot;&lt;/strong&gt; for example is an AI-powered tool that simplifies the creation of Function nodes. You only need to provide a prompt, and the assistant generates the Function nodes for you.&lt;/p&gt;
&lt;p&gt;For more details on using the FlowFuse Assistant, visit &lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;the Assistants Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion%3A&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/why-should-you-use-node-red-function-nodes/#conclusion%3A&quot;&gt;Conclusion:&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Function nodes are particularly valuable for users who possess JavaScript programming skills. They allow for complex tasks, advanced data manipulation, and integration with external APIs, providing a high level of customization and flexibility. However, they require a good understanding of JavaScript to implement effectively and can be more challenging to manage and debug compared to standard Node-RED nodes.&lt;/p&gt;
&lt;p&gt;On the other hand, standard Node-RED nodes offer a simpler and more accessible approach, making it easy for users without programming expertise to create and maintain flows. They are designed for straightforward tasks and provide modularity, benefiting from a supportive community for troubleshooting and knowledge sharing.&lt;/p&gt;
&lt;p&gt;Ultimately, the choice between using function nodes and standard nodes will depend on your project&#39;s requirements and your familiarity with JavaScript. If you seek deep customization and flexibility, function nodes—enhanced by tools like FlowFuse Assistant—might be the best choice. For those who value simplicity and ease of use, standard Node-RED nodes are a great fit.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/</id>
        <title>FlowFuse v1.5 Now Available</title>
        <summary>Updates to UI and architecture to allow for future features and Node-RED 3.1.0 Beta Available!</summary>
        <updated>2023-03-16T15:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;For FlowFuse 1.5 we have been busy making a lot of UX changes and upgrading our underlying architecture to enable future innovations on the FlowFuse platform.&lt;/p&gt;
&lt;p&gt;With our recently announced &lt;a href=&quot;https://flowfuse.com/blog/2023/03/terminology-changes/&quot;&gt;Terminology Changes&lt;/a&gt;, we have introduced some new concepts into FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application&lt;/strong&gt;: A group of Node-RED Instances Each instance can run locally (in FlowFuse) or remotely (on Devices)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instances&lt;/strong&gt;: We renamed &amp;quot;Projects&amp;quot; to &amp;quot;Instances&amp;quot; to be more inline with the terminology used in the Node-RED community&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As such, our User Experience has been updated to reflect these changes, and allow for further functionality to be introduced with our plans for &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1689&quot;&gt;Multiple Instances per Application&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;%22applications%22-view&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#%22applications%22-view&quot;&gt;&amp;quot;Applications&amp;quot; View&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the top-level in FlowFuse, you can now see a list of your &amp;quot;Appications&amp;quot;. In FlowFuse 1.5, as we still have a 1:1 relationship of Applications to Local Instances, this will be the same as the list of &amp;quot;Projects&amp;quot; that you&#39;re used to seeing.&lt;/p&gt;
&lt;p&gt;![Screenshot to show the new &amp;quot;Applications&amp;quot; view](./images/screenshot-applications.png &amp;quot;Screenshot to show the new &amp;quot;Applications&amp;quot; view&amp;quot;)&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 text-center&quot;&gt;&lt;b&gt;&quot;Applications&quot; view in FlowFuse, listing all available Applications&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;For 1.5, all of your settings, environment variables, etc. are all now at the &amp;quot;Instance&amp;quot; level. Applications will gain a lot more functionality in future releases.&lt;/p&gt;
&lt;h3 id=&quot;%22instances%22-view&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#%22instances%22-view&quot;&gt;&amp;quot;Instances&amp;quot; View&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When clicking on one of your Applications, you will see a list of Node-RED instances bound to that Application.&lt;/p&gt;
&lt;p&gt;![Screenshot to show the new &amp;quot;Instances&amp;quot; view](./images/screenshot-instances.png &amp;quot;Screenshot to show the new &amp;quot;Instances&amp;quot; view&amp;quot;)&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 text-center&quot;&gt;&lt;b&gt;A list of Instances contained within a single Application.&lt;/b&gt;&lt;/figcaption&gt;
&lt;p&gt;Clicking on this Instance, will open up the &amp;quot;Instance&amp;quot; view, this is an exact replica of the &amp;quot;Project&amp;quot; view you&#39;ll be used to seeing in FlowFuse, and contains all of the same functionality:&lt;/p&gt;
&lt;p&gt;![Screenshot to show the new &amp;quot;Instances&amp;quot; view](./images/screenshot-instance.png &amp;quot;Screenshot to show the new &amp;quot;Instances&amp;quot; view&amp;quot;)&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 text-center&quot;&gt;&lt;b&gt;FlowFuse 1.5&#39;s &quot;Instance&quot; view. This contains all of the functionality previously found in the &quot;Project&quot; view.&lt;/b&gt;&lt;/figcaption&gt;
&lt;h3 id=&quot;devices-%26-managing-remote-instances&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#devices-%26-managing-remote-instances&quot;&gt;Devices &amp;amp; Managing Remote Instances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Devices are now bound to &amp;quot;Instances&amp;quot;, you&#39;ll see these in the &amp;quot;Devices&amp;quot; view, and can be managed and deployed to in exactly the same way as before. Devices will run whatever you&#39;ve selected as your &amp;quot;Target Snapshot&amp;quot; for this Instance.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot to show an Instance&#39;s &#39;Devices&#39; view&quot; alt=&quot;&amp;quot;Screenshot to show an Instance&#39;s &#39;Devices&#39; view&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/screenshot-devices.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;figcaption class=&quot;-mt-6 text-center&quot;&gt;&lt;b&gt;&quot;Devices&quot; view, available for a given Node-RED Instance. This lists all of the connected devices to a given instance, that will automatically update when a new Target Snapshot is set.&lt;/b&gt;&lt;/figcaption&gt;
&lt;h2 id=&quot;node-red-3.1-beta-available&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#node-red-3.1-beta-available&quot;&gt;Node-RED 3.1 Beta Available&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse Cloud is a great place to try out the new Node-RED features, with FlowFuse Cloud now including the &lt;a href=&quot;https://discourse.nodered.org/t/node-red-3-1-0-beta-2-released/76192&quot;&gt;Node-RED 3.1.0-beta.2&lt;/a&gt;. If you want to try this version you can &lt;a href=&quot;https://flowfuse.com/docs/user/instance-settings/#copy-instance&quot;&gt;duplicate your application&lt;/a&gt; or &lt;a href=&quot;https://flowfuse.com/docs/user/changestack/&quot;&gt;upgrade your stack&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;other-improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#other-improvements&quot;&gt;Other Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Update to audit logs to improve usability [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1800&quot;&gt;#1800&lt;/a&gt;] [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1785&quot;&gt;#1785&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Improve how licensing works with overages, for easier scaling of FlowFuse and your Node-RED Instances [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1639&quot;&gt;#1639&lt;/a&gt;] [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1739&quot;&gt;#1739&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Device &amp;quot;Last Seen&amp;quot; status shows &amp;quot;never&amp;quot; even though it has previously been seen [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1723&quot;&gt;#1723&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Improved Safe Mode launch for small projects [&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1579&quot;&gt;#1579&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.5.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That&#39;s also a great place to send us any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;You can also get help on &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;the Node-RED forums&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As well as in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/discussions&quot;&gt;forum within our Github project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/terminology-changes/</id>
        <title>Terminology Changes</title>
        <summary>Applications, Instances &amp; Devices - the new way forward for FlowFuse</summary>
        <updated>2023-03-16T14:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/terminology-changes/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;As a new product in the market, we constantly have to make choices on how to name things. Naming things is hard! As you name a thing, say &amp;quot;Project&amp;quot;, it might be suitable now, but the product evolves, and may outgrow the name such that it doesn’t fit anymore.&lt;/p&gt;
&lt;p&gt;We are at this point with FlowFuse, and want to walk you through what we have planned, and why we are changing a couple of things.&lt;/p&gt;
&lt;h3 id=&quot;enter-the-%22application%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/terminology-changes/#enter-the-%22application%22&quot;&gt;Enter the &amp;quot;Application&amp;quot;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://flowfuse.com/blog/2023/03/flowforge-1-5-0-released/&quot;&gt;FlowFuse 1.5&lt;/a&gt;, we have introduced a new concept called an &lt;strong&gt;Application&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;An Application will allow you to organize multiple Node-RED instances into a single managed group.&lt;/p&gt;
&lt;p&gt;As of the 1.5 release, an Application can still only have a single Node-RED instance, but in future releases, Applications will allow for multiple Node-RED instances and will allow us to implement capabilities such as &lt;strong&gt;DevOps Pipelines&lt;/strong&gt; and &lt;strong&gt;High Availability&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;%22projects%22-to-%22instances%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/terminology-changes/#%22projects%22-to-%22instances%22&quot;&gt;&amp;quot;Projects&amp;quot; to &amp;quot;Instances&amp;quot;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Until now, &#39;Project&#39; encapsulated both the Node-RED instance that was running in FlowFuse, and the associated devices (remote instances), settings and environment variables. It was an overloaded term, and it caused confusion with our users.&lt;/p&gt;
&lt;p&gt;To simplify things, and to adhere more to the terminology familiar with the Node-RED community, we are renaming Projects to &lt;strong&gt;Instances&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;Instance&lt;/strong&gt; is a customized version of Node-RED that includes various FlowFuse plugins to integrate it with the FlowFuse platform. It can also be used to manage the environment variables used in your Node-RED flows.&lt;/p&gt;
&lt;p&gt;Instances can either be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Local&lt;/strong&gt; - An instance of Node-RED running in FlowFuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote&lt;/strong&gt; - An instance of Node-RED, managed by FlowFuse, running on a Device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In future releases, environment variables will also be able to be stored at the Application level, and shared across multiple Node-RED Instances.&lt;/p&gt;
&lt;h3 id=&quot;devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/terminology-changes/#devices&quot;&gt;Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FlowFuse can also be used to manage remote Node-RED instances. This is typically useful when you have a number of remote devices that are required to run the same Node-RED instance, and may have variation in configuration or environment variables for example.&lt;/p&gt;
&lt;p&gt;Devices are registered to an Instance, and can be configured to run &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#snapshot&quot;&gt;Snapshots&lt;/a&gt; of the Instance running in FlowFuse.&lt;/p&gt;
&lt;p&gt;To accomplish this remote management capability, the &lt;a href=&quot;https://github.com/FlowFuse/device-agent&quot;&gt;FlowFuse Device Agent&lt;/a&gt; needs to be installed on each device. Devices are registered with a Team, and then the appropriate device(s) are assigned to a Node-RED instance that should be deployed to the device(s). When the Node-RED instance is ready for deployment, a user creates a snapshot of the instance and marks it as a target snapshot for the device.&lt;/p&gt;
&lt;p&gt;We hope these changes will simplify the FlowFuse terminology for our users and allow us to grow the FlowFuse platform. If you have any feedback or thoughts, please do reach out to us.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/</id>
        <title>Node-RED Tips - Smooth, Catch, and Math</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-03-13T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-use-the-smooth-node-to-get-the-minimum-and-maximum-values-of-your-payloads&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/#1.-use-the-smooth-node-to-get-the-minimum-and-maximum-values-of-your-payloads&quot;&gt;1. Use the Smooth node to get the minimum and maximum values of your payloads&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When taking data in from sensors sometimes a spurious value can be sent into your flow. This can result in oddities in a graph or even misfiring of actions such as turning on a heating system. The Smooth custom node allows you to store the min and max of a payload for the last few messages received.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using the Smooth node to return highest value from the last 100 payloads&quot; alt=&quot;Using the Smooth node to return highest value from the last 100 payloads&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/smooth.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can in turn use this to ignore values that deviate too far from the sample. To help demonstrate the Smooth node, I&#39;ve created a flow you can import into Node-RED.&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-15&quot;&gt;
  &lt;pre class=&quot;language-json&quot;&gt;&lt;code id=&quot;code-15&quot; class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9484c25a0120bd48&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Automatically outputs random value (temperature in Celcius) between 0 &amp;amp; 25 every second&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;nodes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e4f972f9daad6246&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c7fc075a1915e87b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;966a772c46dc2888&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;574&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;82&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e4f972f9daad6246&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link out&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9484c25a0120bd48&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link out 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;links&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;33594c64783cdc45&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e6bf7b494b48861e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;355&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c7fc075a1915e87b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;inject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9484c25a0120bd48&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;props&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;repeat&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;crontab&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;once&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;onceDelay&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;topic&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;966a772c46dc2888&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;966a772c46dc2888&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;random&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9484c25a0120bd48&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;low&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;25&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;inte&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;260&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e4f972f9daad6246&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Calculate average, high and low, save to flow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;nodes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cc3978c7c4ea56ed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e1819526a5f365c8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;33594c64783cdc45&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fea261a15b3b7683&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e28a69232f1cac53&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aecb1727be523240&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e30039ee13e480a8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;259&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;552&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cc3978c7c4ea56ed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;set&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;p&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;pt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;310&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aecb1727be523240&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e1819526a5f365c8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;set&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;p&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;low&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;pt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;310&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e30039ee13e480a8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;33594c64783cdc45&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link in 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;links&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c07b2e101cecbd3b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e4f972f9daad6246&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;75&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;320&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e28a69232f1cac53&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fea261a15b3b7683&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fea261a15b3b7683&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;smooth&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Min&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;100&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;round&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;mult&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;single&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reduce&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e1819526a5f365c8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e28a69232f1cac53&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;smooth&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Max&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;100&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;round&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;mult&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;single&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reduce&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;170&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cc3978c7c4ea56ed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aecb1727be523240&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug 23&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tosidebar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tostatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;complete&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;targetType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusVal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e30039ee13e480a8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;37380f26e8bfc98a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug 25&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tosidebar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tostatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;complete&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;targetType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusVal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;360&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Evaluate if an incoming value is between flow.high and flow.low, if it is not, send the message down a different wire and show an alert in debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;nodes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9393c22b2e3c1ec8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1cd18307cb919159&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;7c1f474e646765a7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a209cd10f33ec401&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;f4b15283e55babf4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e6bf7b494b48861e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;419&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1032&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;162&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9393c22b2e3c1ec8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;switch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Was the value between flow.high and flow.low?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;propertyType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;btwn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;vt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;v2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;low&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;v2t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;else&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;checkall&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;repair&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;outputs&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1cd18307cb919159&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;7c1f474e646765a7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a209cd10f33ec401&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1cd18307cb919159&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug 15&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tosidebar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tostatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;complete&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusVal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;560&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;460&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;7c1f474e646765a7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug 16&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tosidebar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tostatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;complete&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusVal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;560&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;540&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a209cd10f33ec401&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Alert to debug when value is outside of the range&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;set&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;p&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;pt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;The value was outside of the range&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tot&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;str&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;property&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;690&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;f4b15283e55babf4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;f4b15283e55babf4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;debug 17&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tosidebar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;tostatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;complete&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusVal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;statusType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;960&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e6bf7b494b48861e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link in&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ec11a9ee9148b0b5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link in 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;links&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e4f972f9daad6246&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c07b2e101cecbd3b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;75&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;9393c22b2e3c1ec8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;caf4214602d5f2c9&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Manually send a spurious value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;nodes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;14097fb7ba3a9ecc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c07b2e101cecbd3b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;159&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;232&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;82&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;14097fb7ba3a9ecc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;inject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;caf4214602d5f2c9&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;props&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;p&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;repeat&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;crontab&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;once&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;!&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;onceDelay&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;topic&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;75&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;payloadType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;num&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c07b2e101cecbd3b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;c07b2e101cecbd3b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link out&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;z&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dd95c0bca1101c86&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;g&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;caf4214602d5f2c9&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link out 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;link&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;links&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;33594c64783cdc45&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e6bf7b494b48861e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;225&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;wires&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-15&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;h3 id=&quot;2.-perform-simple-maths-functions-using-jsonata-in-change-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/#2.-perform-simple-maths-functions-using-jsonata-in-change-nodes&quot;&gt;2. Perform simple maths functions using JSONata in Change nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can perform basic maths functions using the Change node and JSONata. Let&#39;s say you wanted to take a payload and multiply it by a value. You could use a custom node such as &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-calc&quot;&gt;node-red-contrib-calc&lt;/a&gt; but you can also easily complete the same task within a change node.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using JSONata in a Change node to multiply a payload by 2.5&quot; alt=&quot;Using JSONata in a Change node to multiply a payload by 2.5&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/jsonata.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This will take the input payload, multiply it by 2.5 then output it as the new payload. You can try this out using the code below.&lt;/p&gt;
&lt;div id=&quot;nr-flow-153&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow153 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;6bbe9c1e81c4ee39&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;cfe9fec308e144db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;2&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:400,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;07aa636f3db17775&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;07aa636f3db17775&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;cfe9fec308e144db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;msg.payload * 2.5&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;jsonata&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:520,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;8bde558e6e2f8551&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;8bde558e6e2f8551&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;cfe9fec308e144db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 26&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;false&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:680,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;1c04633997beb150&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;cfe9fec308e144db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;3&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:440,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;07aa636f3db17775&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;bc52c3d2f38115b1&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;cfe9fec308e144db&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[{&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;}],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;payload&#92;&quot;:&#92;&quot;4&#92;&quot;,&#92;&quot;payloadType&#92;&quot;:&#92;&quot;num&#92;&quot;,&#92;&quot;x&#92;&quot;:350,&#92;&quot;y&#92;&quot;:480,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;07aa636f3db17775&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow153.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-153&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;3.-use-the-catch-node-to-trigger-flows-on-errors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/#3.-use-the-catch-node-to-trigger-flows-on-errors&quot;&gt;3. Use the Catch node to trigger flows on errors&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes you might be working with nodes which don&#39;t output anything when they error or maybe output text directly to debug. This makes it difficult for you to run flows when something fails. For example, when using the Read File node, where the expected file is not found, it would be useful to be able to run a specific flow which sends an alert.&lt;/p&gt;
&lt;p&gt;You can do this using the Catch node. Drop the node onto your workspace then select if you want errors from some or all nodes. For this example I am going to select just the Read File node. If I then rerun the flow I get an error message out of the Catch node every time there is an error with reading the file.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Catching an error from the Read File node and outputting a message to debug&quot; alt=&quot;Catching an error from the Read File node and outputting a message to debug&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/catch.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Note that there are no wires connecting the flow to the error output. This means you can have a single Catch node monitoring a whole project and logging errors as well as sending alerts as needed. You can import the flows from this example using the code below.&lt;/p&gt;
&lt;div id=&quot;nr-flow-154&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow154 = &quot;&#92;n[{&#92;&quot;id&#92;&quot;:&#92;&quot;d6399c6fddb572ef&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;debug&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0c6a2ba248b5933f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;debug 28&#92;&quot;,&#92;&quot;active&#92;&quot;:true,&#92;&quot;tosidebar&#92;&quot;:true,&#92;&quot;console&#92;&quot;:false,&#92;&quot;tostatus&#92;&quot;:false,&#92;&quot;complete&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;targetType&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;statusVal&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;statusType&#92;&quot;:&#92;&quot;auto&#92;&quot;,&#92;&quot;x&#92;&quot;:1100,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[]},{&#92;&quot;id&#92;&quot;:&#92;&quot;de70fda720070c57&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;inject&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0c6a2ba248b5933f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;props&#92;&quot;:[],&#92;&quot;repeat&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;crontab&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;once&#92;&quot;:false,&#92;&quot;onceDelay&#92;&quot;:0.1,&#92;&quot;topic&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;a18f9c8638c78e57&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;a18f9c8638c78e57&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;file in&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0c6a2ba248b5933f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;filename&#92;&quot;:&#92;&quot;example.txt&#92;&quot;,&#92;&quot;filenameType&#92;&quot;:&#92;&quot;str&#92;&quot;,&#92;&quot;format&#92;&quot;:&#92;&quot;utf8&#92;&quot;,&#92;&quot;chunk&#92;&quot;:false,&#92;&quot;sendError&#92;&quot;:false,&#92;&quot;encoding&#92;&quot;:&#92;&quot;none&#92;&quot;,&#92;&quot;allProps&#92;&quot;:false,&#92;&quot;x&#92;&quot;:930,&#92;&quot;y&#92;&quot;:260,&#92;&quot;wires&#92;&quot;:[[]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;2dbb0cc4bc10d0bc&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;catch&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0c6a2ba248b5933f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;scope&#92;&quot;:[&#92;&quot;a18f9c8638c78e57&#92;&quot;],&#92;&quot;uncaught&#92;&quot;:false,&#92;&quot;x&#92;&quot;:790,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;b22988df6357a52a&#92;&quot;]]},{&#92;&quot;id&#92;&quot;:&#92;&quot;b22988df6357a52a&#92;&quot;,&#92;&quot;type&#92;&quot;:&#92;&quot;change&#92;&quot;,&#92;&quot;z&#92;&quot;:&#92;&quot;0c6a2ba248b5933f&#92;&quot;,&#92;&quot;name&#92;&quot;:&#92;&quot;Debug message&#92;&quot;,&#92;&quot;rules&#92;&quot;:[{&#92;&quot;t&#92;&quot;:&#92;&quot;set&#92;&quot;,&#92;&quot;p&#92;&quot;:&#92;&quot;payload&#92;&quot;,&#92;&quot;pt&#92;&quot;:&#92;&quot;msg&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;There was an error reading the file&#92;&quot;,&#92;&quot;tot&#92;&quot;:&#92;&quot;str&#92;&quot;}],&#92;&quot;action&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;property&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;from&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;to&#92;&quot;:&#92;&quot;&#92;&quot;,&#92;&quot;reg&#92;&quot;:false,&#92;&quot;x&#92;&quot;:940,&#92;&quot;y&#92;&quot;:300,&#92;&quot;wires&#92;&quot;:[[&#92;&quot;d6399c6fddb572ef&#92;&quot;]]}]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow154.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-154&#39;) })&lt;/script&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;simplifying-multi-instance-communication-with-flowfuse-project-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-4/#simplifying-multi-instance-communication-with-flowfuse-project-nodes&quot;&gt;Simplifying Multi-Instance Communication with FlowFuse Project Nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Coordinating communication between multiple Node-RED instances can be challenging, but FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;Project Nodes&lt;/a&gt; make it effortless. With these nodes, you can seamlessly send messages between instances without dealing with complicated network configurations.&lt;/p&gt;
&lt;p&gt;Simply choose the target instance by name, and FlowFuse handles the connection automatically. This streamlines the management of multi-instance environments, ensuring smooth communication between flows across different devices or locations. Whether you&#39;re handling multiple projects or managing large-scale systems, FlowFuse Project Nodes help you save time and minimize errors.&lt;/p&gt;
&lt;p&gt;FlowFuse continues to push the boundaries of collaboration and scalability in Node-RED projects. For more details on these features, visit the &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse website&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/</id>
        <title>Comparing Node-RED Dashboards Solutions</title>
        <summary>One of the most common features Node-RED users add to their flows is a dashboard, we compaure the 3 most popular options.</summary>
        <updated>2023-03-13T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Dashboards are a great feature of Node-RED, allowing you to easily expose data visualisations and interactive elements of your flows to users via a web browser. I often see discussions in the community about which dashboard option is best for any given scenario, I wanted to compare the most popular options as they stand in early 2023.&lt;/p&gt;
&lt;div class=&quot;blog-update-notes&quot;&gt;
    &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; Since this article was published, it&#39;s worth noting a couple of important updates:&lt;/p&gt;
    &lt;ul&gt;
        &lt;li&gt;FlexDash is no longer maintained and supported.&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0&lt;/a&gt; has been released, which is a new, modern dashboard stack for Node-RED, and offers all of the benefits of the original &quot;Node-RED Dashboard&quot;, plus more.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;which-dashboards-am-i-going-to-consider%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#which-dashboards-am-i-going-to-consider%3F&quot;&gt;Which dashboards am I going to consider?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Based on their downloads per week and active development, I believe there are 3 main dashboards worth considering. In no particular order, they are &lt;a href=&quot;https://flows.nodered.org/node/node-red-dashboard&quot;&gt;Dashboard&lt;/a&gt;, &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-uibuilder&quot;&gt;uibuilder&lt;/a&gt;, and &lt;a href=&quot;https://flows.nodered.org/node/@flexdash/node-red-fd-corewidgets&quot;&gt;FlexDash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s not to say that there are not other options, I am focusing on the dashboards I believe are popular in the Node-RED community.&lt;/p&gt;
&lt;p&gt;I&#39;d like to take this opportunity to thank the project leads for each of the three dashboards for responding to me and providing their take on the current state and future development of each. Where possible I have quoted their words, either from their messages to me or from the projects&#39; documentation. Thanks to &lt;a href=&quot;https://github.com/dceejay&quot;&gt;Dave&lt;/a&gt;, &lt;a href=&quot;https://github.com/TotallyInformation&quot;&gt;Julian&lt;/a&gt;, and &lt;a href=&quot;https://github.com/tve&quot;&gt;Thorsten&lt;/a&gt; for their replies as well as all the work they&#39;ve put into these great projects!&lt;/p&gt;
&lt;h2 id=&quot;methodology&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#methodology&quot;&gt;Methodology&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To compare these dashboards, I am going to consider each of them based on the following factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How easy is it to install?&lt;/li&gt;
&lt;li&gt;How easy is it to get your first demo dashboard running?&lt;/li&gt;
&lt;li&gt;How extensive is the collection of UI elements?&lt;/li&gt;
&lt;li&gt;How good is the support and documentation?&lt;/li&gt;
&lt;li&gt;How &#39;cloud native&#39; is the dashboard?&lt;/li&gt;
&lt;li&gt;How active is each project&#39;s development?&lt;/li&gt;
&lt;li&gt;What are the future development plans?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am assuming the user is a low-code developer. They may have limited experience with coding and are most comfortable working in visual interfaces.&lt;/p&gt;
&lt;p&gt;So, that&#39;s the methodology, let&#39;s get on with looking at the strengths of each project.&lt;/p&gt;
&lt;h2 id=&quot;how-easy-is-it-to-install%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-easy-is-it-to-install%3F&quot;&gt;How easy is it to install?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;uibuilder---1st-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---1st-place&quot;&gt;uibuilder - 1st place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A search on Google for uibuilder returns the correct custom node. When searching for the custom node in the palette manager there is only one result, this is great as users are very likely to install what they were searching for. Once you&#39;ve found the correct custom node, the installation takes just a few moments using the palette manager.&lt;/p&gt;
&lt;h3 id=&quot;dashboard---2nd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#dashboard---2nd-place&quot;&gt;Dashboard - 2nd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As Dashboard is currently the most popular solution to build dashboards in Node-RED, it&#39;s very easy to find both in search engines and in the Node-RED interface. A Google search brings up the correct custom node. Finding this custom node in Node-RED&#39;s palette manager is not quite as easy, at the time of writing it&#39;s the third from top result for the search term &#39;dashboard&#39;. Some users might not select the intended item from the palette manager on first attempt. However, once you have found the correct custom node, installation is easy and takes just a few moments.&lt;/p&gt;
&lt;h3 id=&quot;flexdash---3rd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash---3rd-place&quot;&gt;FlexDash - 3rd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When searching for &#39;FlexDash node red&#39; on Google, the top result is the Node-RED website for the custom node. The issue with this, and this is also a problem when searching in the palette manager, is the project &#39;FlexDash&#39; is apparently not what we actually need to install. When reading the readme for the project on Github it says &lt;em&gt;&#39;You most likely do not want to explicitly install this package, you want to install the &lt;a href=&quot;https://github.com/flexdash/node-red-fd-corewidgets&quot;&gt;core widgets&lt;/a&gt;, which will bring in this package and more and will provide a usable whole&#39;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Credit to the developers for adding in this helpful text but I suspect most users will start off by installing FlexDash then later discover that was not the correct way to proceed. It would be great if the custom node which needs to be installed was the one called &#39;FlexDash&#39; in my opinion.&lt;/p&gt;
&lt;p&gt;This problem is compounded by there being no help file at all for &#39;FlexDash&#39; showing up on the Node-RED web site. That may well be a deliberate attempt to help users get the right custom node installed, but it was still a confusing start for me and I suspect other users will have a similar experience.&lt;/p&gt;
&lt;p&gt;When setting up FlexDash, one thing that wasn&#39;t immediately obvious was that I needed to restart Node-RED before the custom node showed in the palette. This step is &lt;a href=&quot;https://flexdash.github.io/docs/quick-start/#installing-flexdash-in-node-red&quot;&gt;covered in the docs&lt;/a&gt; but I suspect a lot of users will get stuck working out why the palette manager says the custom node is installed but nothing new has been added to the palette.&lt;/p&gt;
&lt;p&gt;There is also an &lt;a href=&quot;https://github.com/node-red/node-red/issues/569&quot;&gt;ongoing discussion&lt;/a&gt; about a way to resolve issue by changing how Node-RED deals with dependencies which sounds promising.&lt;/p&gt;
&lt;p&gt;I believe a few improvements to the install process could make FlexDash a much more popular custom node.&lt;/p&gt;
&lt;h2 id=&quot;how-easy-is-it-to-get-your-first-demo-dashboard-running%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-easy-is-it-to-get-your-first-demo-dashboard-running%3F&quot;&gt;How easy is it to get your first demo dashboard running?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flexdash---1st-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash---1st-place&quot;&gt;FlexDash - 1st place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Getting an example dashboard up and running in FlexDash is very easy thanks to the example flows which are included in the package. Simply go to &#39;Import&#39;, &#39;Examples&#39; then select &#39;Hello-world&#39; from the example flows. Now deploy and add /flexdash to the end of the URL of your Node-RED editor and you should have your first dashboard running.&lt;/p&gt;
&lt;h3 id=&quot;uibuilder---2nd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---2nd-place&quot;&gt;uibuilder - 2nd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It was quite simple to get an example dashboard up and running in uibuilder. As with FlexDash, there are examples you can import. Once we import an example we do start to see the significantly different approach to delivering dashboards with uibuilder to the other two solutions. The examples seem to demonstrate how you could build a dashboard rather than showing specific UI elements such as charts in use.&lt;/p&gt;
&lt;h3 id=&quot;dashboard---3rd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#dashboard---3rd-place&quot;&gt;Dashboard - 3rd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Getting your first dashboard running in Dashboard is quite easy, once installed you need to drag in a Dashboard UI element then assign that to a UI group and tab. The group and tab can be left as their default options (home) which I suspect most users will work out quickly.&lt;/p&gt;
&lt;p&gt;You then need to deploy your flow and visit the dashboard using &#39;/ui&#39; on the end of the URL of your Node-RED editor and you are up and running.&lt;/p&gt;
&lt;p&gt;Dashboard would benefit from some example flows as we see with the other two custom nodes.&lt;/p&gt;
&lt;h2 id=&quot;how-extensive-is-the-collection-of-ui-elements%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-extensive-is-the-collection-of-ui-elements%3F&quot;&gt;How extensive is the collection of UI elements?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;flexdash-and-dashboard---joint-1st-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash-and-dashboard---joint-1st-place&quot;&gt;FlexDash and Dashboard - joint 1st place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s really hard to separate these two, when considering the UI elements they come with. They both have out of the box solutions for charts, gauges, buttons, drop downs, toggles, text etc. I think they both deserve 1st place in this category.&lt;/p&gt;
&lt;h3 id=&quot;uibuilder---3rd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---3rd-place&quot;&gt;uibuilder - 3rd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is possibly a little unfair on uibuilder. Arguably by design, uibuilder does not currently include many UI elements. To add most useful elements (charts, gauges etc) to your dashboard, you will need to set out your design in HTML or look at using one of the supported frontend frameworks. This makes uibuilder more versatile for users who are comfortable using code to set out dashboards but for the low-coders among us it&#39;s less ideal.&lt;/p&gt;
&lt;h2 id=&quot;how-good-is-the-support-and-documentation%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-good-is-the-support-and-documentation%3F&quot;&gt;How good is the support and documentation?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;all-three---joint-first-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#all-three---joint-first-place&quot;&gt;All three - joint first place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All three projects have an active community and good support documentation. Where as I may have a personal preference about how I like documentation to be set out, I don&#39;t think that makes any one project better than the rest.&lt;/p&gt;
&lt;h2 id=&quot;how-&#39;cloud-native&#39;-is-the-dashboard%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-&#39;cloud-native&#39;-is-the-dashboard%3F&quot;&gt;How &#39;cloud native&#39; is the dashboard?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the words of the &lt;a href=&quot;https://www.cncf.io/&quot;&gt;Cloud Native Computing Foundation&lt;/a&gt; &#39;&lt;em&gt;Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;p&gt;&#39;&lt;em&gt;These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;p&gt;So, how well does each project conform to these ideals?&lt;/p&gt;
&lt;h3 id=&quot;dashboard---1st-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#dashboard---1st-place&quot;&gt;Dashboard - 1st place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dashboard stores all configuration data within the Node-RED instance. When deploying an existing Node-RED project to a new instance everything just works exactly as it did previously.&lt;/p&gt;
&lt;h3 id=&quot;flexdash---2nd-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash---2nd-place&quot;&gt;FlexDash - 2nd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As with Dashboard, everything required to define each dashboard is stored within Node-RED. This makes redeployment trivial. Unfortunately, as the Node-RED instance currently needs to be restarted before FlexDash works, it just missed out on joint first place. It would be great to see that issue resolved in future versions. There is also an &lt;a href=&quot;https://github.com/node-red/node-red/issues/569&quot;&gt;ongoing discussion&lt;/a&gt; about a way to resolve issue by changing how Node-RED deals with dependencies.&lt;/p&gt;
&lt;h3 id=&quot;uibuilder---3rd-place-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---3rd-place-1&quot;&gt;uibuilder - 3rd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;uibuilder uses the filesystem of the host instance to store its configuration. In practice this means that if you migrate the Node-RED project files to a new location you probably will find your dashboard no longer works. This can be mitigated by also migrating the filesystem (for example using persistent storage in Docker) and re-deploying via a Docker registry but it would be great to see uibuilder move towards not being dependant on the filesystem as it will make DevOps tasks that much easier.&lt;/p&gt;
&lt;h2 id=&quot;how-active-is-each-project&#39;s-development%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#how-active-is-each-project&#39;s-development%3F&quot;&gt;How active is each project&#39;s development?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;uibuilder---1st-place-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---1st-place-1&quot;&gt;uibuilder - 1st place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the uibuilder Github Commits&quot; alt=&quot;Image showing the uibuilder Github Commits&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/uibuilder-activity.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;uibuilder has has consistent commits to the project going back several years with even greater activity since the start of 2022.&lt;/p&gt;
&lt;h3 id=&quot;flexdash---2nd-place-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash---2nd-place-1&quot;&gt;FlexDash - 2nd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the FlexDash Github Commits&quot; alt=&quot;Image showing the FlexDash Github Commits&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flexdash-activity.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The commits to FlexDash have been regular since mid 2022.&lt;/p&gt;
&lt;h3 id=&quot;dashboard---3rd-place-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#dashboard---3rd-place-1&quot;&gt;Dashboard - 3rd place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the Dashboard Github Commits&quot; alt=&quot;Image showing the Dashboard Github Commits&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/dashboard-activity.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Dashboard is now in a a maintenance only state. In the words of the project lead, &lt;em&gt;&#39;Angular 1 (the framework used to build Dashboard) is now unsupported and it&#39;s just a matter of time before there is a serious security hole raised against it, for which there will be no fix. Of course we don&#39;t use all the features of it so we may be lucky that an exploit doesn&#39;t necessarily expose us directly but it will compromise any audits people may wish to do&#39;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In practice, this means that sooner or later using Dashboard might become a significant security risk.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-future-development-plans%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#what-are-the-future-development-plans%3F&quot;&gt;What are the future development plans?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;uibuilder---joint-firstplace&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#uibuilder---joint-firstplace&quot;&gt;uibuilder - joint firstplace&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;During the writing of this article, uibuilder released a new version with some significant new features. In the words of the project lead when talking about version 6.1.0, &#39;&lt;em&gt;It feels like uibuilder really is growing up. No more apologising for not being a direct Node-RED Dashboard replacement, uibuilder has its own path&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can now create and update visible web page elements direct from Node-RED data without needing to understand all of the intricacies and inconsistencies of HTML. You can create your own utility tools either in Node-RED or in front-end code that leverages the low-code UI features of uibuilder&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;p&gt;It&#39;s great to see projects under active development. My greatest difficulty when using uibuilder, is I found it hard to create the UI elements I needed based on low-code workflows. According to the &lt;a href=&quot;https://totallyinformation.github.io/node-red-contrib-uibuilder/#/roadmap&quot;&gt;development roadmap for uibuilder&lt;/a&gt; the project should progress towards being easier and easier for low-coders to make use of.&lt;/p&gt;
&lt;p&gt;To again quote the project lead, &#39;&lt;em&gt;In general, the ongoing direction of travel is to enable more zero-code features that will work both in Node-RED flows and in front-end custom code. The low-code feature set is already quite mature now and is well documented enough that it can be used by other tools should anyone wish to do so. I will be making sure that both the zero-code and low-code features are as easy to use as possible both from Node-RED and front-end code for maximum flexibility&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;h3 id=&quot;flexdash---joint-firstplace&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#flexdash---joint-firstplace&quot;&gt;FlexDash - joint firstplace&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The project Lead for FlexDash had the following to say about the future development of the project. &#39;&lt;em&gt;FlexDash currently has a fairly rigid overall page structure: there&#39;s a tab bar and each tab&#39;s content is organized in grids of widgets. The plan is to open this up fully so the user can start from a blank page and place containers which contain widgets. This way almost any layout could be implemented in FlexDash&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;p&gt;&#39;&lt;em&gt;I also would like to improve the multi-user capabilities of FlexDash by supporting authentication and making it easier for users to implement flows that present per-user data in the dashboard&lt;/em&gt;&#39;.&lt;/p&gt;
&lt;p&gt;After using FlexDash over the past couple of weeks and finding it to be already be a strong contender for all my Node-RED dashboard needs, it&#39;s great to see it continuing to be improved.&lt;/p&gt;
&lt;h3 id=&quot;dashboard---third-place&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#dashboard---third-place&quot;&gt;Dashboard - third place&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Important Update: New Generation of Node-RED Dashboard Released:&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;A new generation of the outdated and unmaintained Node-RED Dashboard has been released to replace it. Introducing &lt;a href=&quot;https://dashboard.flowfuse.com/&quot;&gt;Node-RED Dashboard 2.0&lt;/a&gt;, built on Vue.js, offering significantly more versatility than its predecessor. This new dashboard, managed by FlowFuse, is designed to allow full customization, addressing the limitations of the previous version.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;*Node-RED Dashboard 2.0 retains most of the widgets and concepts from the old version, so transitioning from Node-RED Dashboard 1.0 to 2.0 is easy. For a full feature comparison you can check out the &lt;a href=&quot;https://dashboard.flowfuse.com/user/migration.html&quot;&gt;Migration Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dashboard 2.0 includes various chart types such as line, scatter, bar, gauge, and more, and it&#39;s compatible with all the &lt;a href=&quot;https://vuetifyjs.com/en/components/all/#containment&quot;&gt;Vuetify component library&lt;/a&gt;, making it easier to build advanced dashboards.*&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Furthermore, the team is continuously working on adding more amazing features to enhance the user experience. For a smooth transition, FlowFuse provides easy-to-follow guides. Refer to &lt;a href=&quot;https://flowfuse.com/blog/dashboard/&quot;&gt;Node-RED Dashboard 2.0 Guides&lt;/a&gt; for more information.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As mentioned above, Dashboard is no longer in active development. This is due to the framework upon which it was build &lt;a href=&quot;https://angularjs.org/&quot;&gt;(AngularJS)&lt;/a&gt; now being unsupported as of the end of 2021. You can read a lot more detail on why ongoing development of Dashboard is not practical in this &lt;a href=&quot;https://discourse.nodered.org/t/discussion-about-a-new-dashboard/51119/3&quot;&gt;thread on the Node-RED forums&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There could possibly be new effort put into porting Dashboard over to a new framework but that is a significant amount of work. I suspect it would take hundreds of hours development just to get the feature set back to the same state as the current version so I suspect it won&#39;t ever happen.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/comparing-node-red-dashboards/#conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Personally, I was a little surprised by these results. I have used Dashboard for around 3 years and always found it to be a great tool for putting together quick and informative dashboards. That being said, when attempting to objectively compare it to uibuilder and FlexDash, the other two projects often are individually better in a given category. That coupled with the halt of development for Dashboard due to AngularJS being no longer supported, it&#39;s hard to recommend Dashboard for totally new Node-RED users in 2023, especially for commercial projects.&lt;/p&gt;
&lt;p&gt;If you already use Dashboard, in a non-commercial setting you should probably continue to do so, you might find that its development slows down to a near stall due to the underlying framework now being abandoned but for at least as of right now it&#39;s a great solution to build your Node-RED dashboards in.&lt;/p&gt;
&lt;p&gt;FlexDash is probably the best low-code solution for building dashboards in Node-RED. If you don&#39;t get blocked by the confusing install process I believe it&#39;s the one to pick up at the time of writing due to it&#39;s ongoing support and low-code interface.&lt;/p&gt;
&lt;p&gt;uibuilder is currently not what I would consider a truly low-code option for creating dashboards but it is moving in that direction. It has some great features and is extremely flexible so it has a good chance of ending up as the most popular solution to build dashboards in Node-RED in the long term. That being said, as of time of writing unless you are a &#39;coder&#39; you will may struggle to build a dashboard using it.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/</id>
        <title>Node-RED Tips - Exec, Filter, and Debug</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-03-07T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-the-exec-node-allows-you-to-interact-with-bash-from-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/#1.-the-exec-node-allows-you-to-interact-with-bash-from-node-red&quot;&gt;1. The Exec node allows you to interact with BASH from Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Exec allows you to run Shell commands and receive the value back into your flow. This opens up almost any command which can be run on the host devices CLI to your Node-RED flows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Example flow using the Exec node&quot; alt=&quot;&amp;quot;Example flow using the Exec node&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/exec-example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;2.-the-filter-node-helps-you-discard-duplicate-messages&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/#2.-the-filter-node-helps-you-discard-duplicate-messages&quot;&gt;2. The Filter node helps you discard duplicate messages&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It can be useful to only allow messages to proceed through a flow where their value is unique. Filter makes that task simple, no need to store the past values and check each new message against a list.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Configuring the Filter node to only allow unique payloads through&quot; alt=&quot;Configuring the Filter node to only allow unique payloads through&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/filter-config.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Once your filter is configured as shown above, try sending different payloads through to see the outcome.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Demonstration showing the Filter node&quot; alt=&quot;Demonstration showing the Filter node&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/filter-example.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;3.-counting-the-amount-of-messages-sent-to-a-debug-node&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/#3.-counting-the-amount-of-messages-sent-to-a-debug-node&quot;&gt;3. Counting the amount of messages sent to a Debug node&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Debug node has a lot of great features that we don&#39;t see used that often. One example is the ability to show a count of how many messages have been sent to that Debug node since the last deploy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Setting up the debug to count messages&quot; alt=&quot;Setting up the debug to count messages&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/setup-counting-debug.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Once you&#39;ve setup the node as shown above, you will see a counter under the debug.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Each message sent to the debug node is counted&quot; alt=&quot;Each message sent to the debug node is counted&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/counting-debug.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;effortless-communication-between-node-red-instances-with-flowfuse-project-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/3-quick-node-red-tips-3/#effortless-communication-between-node-red-instances-with-flowfuse-project-nodes&quot;&gt;Effortless Communication Between Node-RED Instances with FlowFuse Project Nodes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Managing communication between multiple Node-RED instances can be a complex task, but FlowFuse &lt;a href=&quot;https://flowfuse.com/docs/user/projectnodes/&quot;&gt;Project Nodes&lt;/a&gt; simplify this process dramatically. With these nodes, you can easily send messages between different Node-RED instances without worrying about complex configurations or network setup.&lt;/p&gt;
&lt;p&gt;All you need to do is select the target instance by name, and FlowFuse takes care of the rest. This makes it faster and more efficient to handle multi-instance environments, ensuring seamless communication between flows across different devices or locations. Whether you&#39;re managing multiple environments or working on large-scale projects, FlowFuse Project Nodes save you time and reduce the risk of errors.&lt;/p&gt;
&lt;p&gt;FlowFuse continues to innovate, making collaboration and scalability in Node-RED projects even easier. To learn more about these features, check out the &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse website&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/</id>
        <title>Node-RED: The Integration Platform for IIoT Edge Computing &amp; PLCs</title>
        <summary>Node-RED&#39;s Role in IIoT Edge Computing &amp; PLC Integration</summary>
        <updated>2023-03-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Node-RED has become a widely adopted integration platform for IoT edge computing and PLCs. Discover why!&lt;/p&gt;
&lt;h2 id=&quot;the-integration-platform-for-iiot-edge-computing-%26-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#the-integration-platform-for-iiot-edge-computing-%26-plcs&quot;&gt;The Integration Platform for IIoT Edge Computing &amp;amp; PLCs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node-RED is a widely adopted open-source low-code development tool that makes it easy to connect and integrate different sources of data. With a visual programming interface and drag-and-drop functionality, &lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; makes it possible for software developers and non-professional software developers to create sophisticated applications.&lt;/p&gt;
&lt;p&gt;In the manufacturing and industrial automation industry, the focus of the Industrial Internet of Things (IIoT) has been on integrating industrial processes and equipment to enable real-time monitoring, control, and analysis of data. For many use cases, instead of sending all the data to the cloud, the best practice for processing industrial data is to deploy the application to the edge of the network, referred to as edge computing. By processing the data closer to the data source, edge computing has many benefits, including reduced latency, limited downtime, conserving bandwidth, and increased privacy, and security.&lt;/p&gt;
&lt;h2 id=&quot;how-node-red-fits-into-iiot-edge-computing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#how-node-red-fits-into-iiot-edge-computing&quot;&gt;How Node-RED fits into IIoT Edge Computing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A key challenge for IIoT edge computing is the wide variety of different hardware platforms, protocols and sources of data and processes. Over the years, the Node-RED community has built &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;thousands of nodes and flow&lt;/a&gt;s to support a wider range of these sources of data, including support for &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-modbus&quot;&gt;Modbus&lt;/a&gt;, &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-opcua&quot;&gt;OPC-UA&lt;/a&gt;, &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-s7&quot;&gt;S7&lt;/a&gt;, &lt;a href=&quot;https://cookbook.nodered.org/mqtt/&quot;&gt;MQTT&lt;/a&gt;, etc. Node-RED also has nodes for graphics and dashboards to make it trivial to visualize industrial data.&lt;/p&gt;
&lt;p&gt;Node-RED’s visual programming environment makes it accessible to non-developers. Manufacturing, mechanical, and electrical engineers in the factories are typically the domain experts in understanding the existing systems and often lead IIoT initiatives. Node-RED enables these engineers to quickly innovate and create real value for their organizations. This makes it a popular choice for engineers looking to create edge computing solutions.&lt;/p&gt;
&lt;h2 id=&quot;plc-and-iot-gateway-vendors-embrace-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#plc-and-iot-gateway-vendors-embrace-node-red&quot;&gt;PLC and IoT Gateway Vendors Embrace Node-RED&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PLC and IoT Gateway vendors are at the forefront of promoting edge computing. They see edge computing as a way to modernize hardware in the factory and for remote asset management. PLC and IoT gateways often sit in front of old legacy systems that don’t have the connectivity or compute platform to enable IIoT applications.&lt;/p&gt;
&lt;p&gt;Many of these hardware vendors realized they need an application delivery platform for their devices. Traditional OT hardware vendors often implement proprietary software stacks that are often difficult to use and closed to integrating with other hardware and software. Forward thinking hardware vendors realized having an open platform is the future of their industry and customers have begun to demand more open platforms. Node-RED’s ease of use, open community and open source license provided the solution many of these hardware vendors were looking for.&lt;/p&gt;
&lt;h2 id=&quot;the-standard-for-edge-computing-and-plcs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#the-standard-for-edge-computing-and-plcs&quot;&gt;The Standard for Edge Computing and PLCs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today, Node-RED has been adopted by some of the leading PLC and IoT Gateway vendors. The hardware vendor community appears to have standardized on Node-RED as being the edge computing platform for IIoT.&lt;/p&gt;
&lt;p&gt;Below is a sample of the vendors offering a Node-RED solution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.advantech.com/en-eu/products/node-red-gateways/sub_fb7246cc-cc10-486f-806b-30bb50a90f28&quot;&gt;Advantech&lt;/a&gt; Node-RED Field Gateway&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://infosys.beckhoff.com/english.php?content=../content/1033/tf6720_tc3_iot_data_agent/3260672139.html&amp;amp;id=&quot;&gt;Bechhoff&lt;/a&gt; TwinCAT&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bivocom.com/products/iot-gateways/edge-iot-gateway-tg452&quot;&gt;Bivocom&lt;/a&gt; TG452 IoT Edge Gateway&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bliiot.com/edge-computing-gateway-p00359p1.html&quot;&gt;BLIIOT Edge Computing Gateway&lt;/a&gt; EdgeCom BL302&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.community.boschrexroth.com/t5/Store-and-How-to/ctrlX-CORE-Node-RED-App/ba-p/22366&quot;&gt;Bosch CtrlX Core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.broadsens.com/wireless-gateway/&quot;&gt;Broadsens&lt;/a&gt; GU200 &amp;amp; GU 200S&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.emerson.com/documents/automation/product-datasheet-pacedge-software-computing-devices-pacsystems-en-7205588.pdf&quot;&gt;Emerson&lt;/a&gt; PACEdge&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/HilscherAutomation/netPI-nodered&quot;&gt;Hilscher Automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.opto22.com/nodered/general/&quot;&gt;Opto22&lt;/a&gt; groov RIO &amp;amp; EPIC&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.parallaxav.com/controlsystem/&quot;&gt;Parallax AV&lt;/a&gt; Control System&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.particle.io/reference/cloud-apis/node-red/&quot;&gt;Particle.io&lt;/a&gt; Particle&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.pepperl-fuchs.com/usa/en/classid_199.htm?view=productdetails&amp;amp;prodid=93839&quot;&gt;Pepperl+Fuchs&lt;/a&gt; AS-Interface gateway&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://projects.raspberrypi.org/en/projects/getting-started-with-node-red&quot;&gt;Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.renesas.com/us/en/products/programmable-mixed-signal-asic-ip-products/mixed-signal-asics/communication-asics/ftclick-mikrobus-compatible-interface-module&quot;&gt;Renesas&lt;/a&gt; FT Click&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://revolutionpi.com/revpi-connect/&quot;&gt;Revolution Pi&lt;/a&gt; RevPi Connect&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shop.exchange.se.com/en-US/apps/59823/ecostruxure-plant-data-expert/features&quot;&gt;Schneider Electric&lt;/a&gt; ExoStructure Plant Data Expert&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/SIMATICmeetsLinux/IOT2050-NodeRed-OPCUA-Server&quot;&gt;Siemens&lt;/a&gt; S7 PLC&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://st-one.io/en/&quot;&gt;ST-One&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.tulip.co/docs/using-node-red-with-edge-mc&quot;&gt;Tulip&lt;/a&gt; Edge MC &amp;amp; Edge IO&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.wago.com/us/edge-devices&quot;&gt;Wago&lt;/a&gt; Edge Controller &amp;amp; Computer&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://catalog.weidmueller.com/procat/Group.jsp;jsessionid=C885C404E7B4B798B23B8A9BB2200513?groupId=(%22group14048963834797%22)&amp;amp;page=Group&quot;&gt;Weidmueller&lt;/a&gt; control web&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are several key reason Node-RED is so popular for IIoT edge computing, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easy User-friendly interface that makes it accessible to manufacturing engineers that might not have a lot of programming experience.&lt;/li&gt;
&lt;li&gt;Large community of open source nodes that integrate with many different OT hardware and protocols.&lt;/li&gt;
&lt;li&gt;Open source community and license making it vendor neutral so competing hardware vendors feel comfortable embracing the platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/integration-platform-for-edge-computing/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;IIoT and edge computing is making software more critical to the manufacturing industry. The flexibility to integrate data from different sources to create innovative data centric solutions is primarily software driven. In partnership with OT hardware vendors, Node-RED’s flexible and easy to use environment provides the platform for manufacturing companies to embrace software to develop IIoT solutions.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/03/community-news-03/</id>
        <title>Community News March 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-03-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/03/community-news-03/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for March 2023, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;h2 id=&quot;upcoming-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#upcoming-events&quot;&gt;Upcoming events&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;node-red-ask-me-anything&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#node-red-ask-me-anything&quot;&gt;Node-RED Ask Me Anything&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back by popular demand, FlowFuse is hosting a monthly Node-RED Ask Me Anything session on March 9th. This is a great opportunity to ask Nick O’Leary, co-creator of Node-RED &amp;amp; FlowFuse CTO, and Rob Marcer, Node-RED FlowFuse Developer Educator your questions about Node-RED. &lt;a href=&quot;https://flowfuse.com/ask-me-anything/ama-nodered/&quot;&gt;Sign-up today to participate&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;devops-for-node-red%3A-an-introduction-to-flowfuse-webinar&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#devops-for-node-red%3A-an-introduction-to-flowfuse-webinar&quot;&gt;DevOps for Node-RED: An Introduction to FlowFuse Webinar&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Join Nick O&#39;Leary, FlowFuse CTO, as he presents an Introduction to FlowFuse and demonstrates FlowFuse’s platform for providing DevOps for Node-RED. This webinar will be on March 30th. &lt;a href=&quot;https://flowfuse.com/webinars/2023/introduction-to-flowforge/&quot;&gt;Register today&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;from-our-blog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#from-our-blog&quot;&gt;From our Blog&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/&quot;&gt;Toward Highly Available Node-RED&lt;/a&gt; - High availability is an often requested feature for Node-RED. This post from FlowFuse CEO discusses our approach to HA for Node-RED.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/02/ming-blog/&quot;&gt;MING Stack for IoT&lt;/a&gt; - MING technology stack include M (Mosquitto/MQTT), InfluxDB, Node-RED and Grafana. Ian Skerrett, FlowFuse Head of Marketing discusses how this tech stack is used for IoT.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=47EvfmJji-k&quot;&gt;Introduction to Node-RED&lt;/a&gt; - An in-depth webinar recording on key Node-RED concepts and demonstration on how to get started with Node-RED.&lt;/p&gt;
&lt;p&gt;Node-RED Quick Tips - Rob Marcer, FlowFuse Developer Educator has a weekly series of Node-RED hints and tips&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/&quot;&gt;Tips #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/&quot;&gt;Tips #2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;from-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#from-the-community&quot;&gt;From the Community&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;node-red-community-survey&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#node-red-community-survey&quot;&gt;Node-RED Community Survey&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Node-RED open source project is running an Node-RED Community Survey. Give your &lt;a href=&quot;https://nodered.org/blog/2023/02/23/community-survey&quot;&gt;feedback on how you are using Node-RED&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;good-alternatives-to-pis-for-your-next-project&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#good-alternatives-to-pis-for-your-next-project&quot;&gt;Good alternatives to Pis for your next project&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Raspberry Pis continue to be difficult to purchase. Eben Upton of the Raspberry Pi Foundation has said that &lt;a href=&quot;https://www.raspberrypi.com/news/supply-chain-update-its-good-news/&quot;&gt;supply should improve this year&lt;/a&gt; but in the mean-time there are some good alternatives you could consider. The Youtube channel &lt;a href=&quot;https://www.youtube.com/@ExplainingComputers&quot;&gt;ExplainingComputers&lt;/a&gt; has shared a &lt;a href=&quot;https://www.youtube.com/watch?v=k8clrUclPIs&quot;&gt;great video covering some of the most popular SBCs&lt;/a&gt; you could use for your next project, it’s worth a watch.&lt;/p&gt;
&lt;h3 id=&quot;custom-node-spotlight---node-red-contrib-os&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#custom-node-spotlight---node-red-contrib-os&quot;&gt;Custom Node Spotlight - node-red-contrib-os&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-os&quot;&gt;OS&lt;/a&gt; is a great custom node which allows you to monitor the performance of the device you are running Node-RED on. It can check RAM usage, disk space, CPU load, and a lot more. It’s really easy to use, we recommend you &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-os&quot;&gt;take a look&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;join-our-team&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/03/community-news-03/#join-our-team&quot;&gt;Join Our Team&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is expanding our team. We have two openings right now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4798023004&quot;&gt;Developer Advocate - Manufacturing &amp;amp; Industrial Automation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4796271004&quot;&gt;DevOps Engineer&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/</id>
        <title>Some questions we didn&#39;t get to in our first webinar</title>
        <summary>There were some great questions from our first webinar that we didn&#39;t get time to answer, we wanted to share those questions and our answers here.</summary>
        <updated>2023-02-27T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There were some great questions from our &lt;a href=&quot;https://www.youtube.com/watch?v=47EvfmJji-k&quot;&gt;first webinar&lt;/a&gt; that we didn&#39;t get time to answer, we wanted to share those questions and our answers here.&lt;/p&gt;
&lt;h3 id=&quot;irvin-asks%2C-&#39;is-it-possible-to-save-the-debug-information-or-data-flow-to-a-storage-like-splunk-or-sql&#39;%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/#irvin-asks%2C-&#39;is-it-possible-to-save-the-debug-information-or-data-flow-to-a-storage-like-splunk-or-sql&#39;%3F&quot;&gt;Irvin asks, &#39;is it possible to save the debug information or data flow to a storage like Splunk or SQL&#39;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hi Irvin, thanks for the question. I suspect you might be better using a custom node which is designed for logging data rather than capturing the debug node content to a database.&lt;/p&gt;
&lt;p&gt;I&#39;ve come across &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-flogger&quot;&gt;Flogger&lt;/a&gt; which seems to do a good job of logging, including support for multiple log files, and built in support for log rotation.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Capturing debug to a log file using Flogger&quot; alt=&quot;Capturing debug to a log file using Flogger&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flogger.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;If you really wanted to log to a database rather than a log file you could create your own logging subflow. Once that&#39;s in place you can drop it into your flow as needed to capture your debug data for later consumption.&lt;/p&gt;
&lt;h3 id=&quot;anonymous-asks-&#39;can-we-make-an-mobile-application-with-node-red-or-can-the-content-only-be-accessed-through-a-web-browser&#39;%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/#anonymous-asks-&#39;can-we-make-an-mobile-application-with-node-red-or-can-the-content-only-be-accessed-through-a-web-browser&#39;%3F&quot;&gt;Anonymous asks &#39;can we make an mobile application with Node-RED or can the content only be accessed through a web browser&#39;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hello Anon&#39;, it would be great if a Node-RED flow could be built into a mobile app. Sadly, there isn&#39;t a simple way to do so at the time of writing.&lt;/p&gt;
&lt;p&gt;Assuming you want an easy way to package up and distribute the functionality you might be best creating a link to where the application is hosted. Both &lt;a href=&quot;https://www.macrumors.com/how-to/add-a-web-link-to-home-screen-iphone-ipad/&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://www.androidauthority.com/add-website-android-iphone-home-screen-3181682/&quot;&gt;Android&lt;/a&gt; support making a home icon. Once added using them is basically the same user experience as a locally installed application.&lt;/p&gt;
&lt;h3 id=&quot;john-asks-&#39;from-the-random-node-example-in-the-webinar%2C-the-node-connected-to-four-different-nodes.-is-there-an-order-to-which-is-invoked-first%3F-can-that-be-controlled&#39;%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/#john-asks-&#39;from-the-random-node-example-in-the-webinar%2C-the-node-connected-to-four-different-nodes.-is-there-an-order-to-which-is-invoked-first%3F-can-that-be-controlled&#39;%3F&quot;&gt;John asks &#39;From the random node example in the webinar, the node connected to four different nodes. Is there an order to which is invoked first? Can that be controlled&#39;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hi John, interesting question, thanks for sending it in. For the sake of any readers who were not an the webinar here is what you are describing.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing the Flow where the random number generator sends a message to 4 nodes at the same time&quot; alt=&quot;&amp;quot;Image showing the Flow where the random number generator sends a message to 4 nodes at the same time&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/chart-flow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;All downstream nodes linked to the same prior node will be triggered at practically the same time.&lt;/p&gt;
&lt;p&gt;You could use a delay node if you want to ensure a particular node is triggered first. It might also make sense to wire your flow in series rather than parallel. This would allow your functions to all execute in a specific order. That being said, in this case all but one of the nodes do not have outputs so using delays might be the only practical option.&lt;/p&gt;
&lt;h3 id=&quot;abdelhamid-asks%2C-&#39;how-can-i-delete-a-subflow&#39;%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/webinar-1-missed-questions/#abdelhamid-asks%2C-&#39;how-can-i-delete-a-subflow&#39;%3F&quot;&gt;Abdelhamid asks, &#39;How can I delete a subflow&#39;?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thanks Abdelhamid, that&#39;s actually really easy to do. Double click the subflow you want to delete, then select &#39;delete subflow&#39; from the top of your workspace.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Image showing how to delete a subflow&quot; alt=&quot;&amp;quot;Image showing how to delete a subflow&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/delete-subflow.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Thanks again to everyone who attended and participated in our first webinar. We have lots of other useful live content coming up soon, you can view and register for future events on our website&#39;s &lt;a href=&quot;https://flowfuse.com/webinars/&quot;&gt;webinars page&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/</id>
        <title>Node-RED Tips - Deploying, Debugging, and Delaying</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-02-23T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software, and Node-RED is no exception. In each of this series of blog posts, we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-deploy-just-what-you&#39;ve-changed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/#1.-deploy-just-what-you&#39;ve-changed&quot;&gt;1. Deploy just what you&#39;ve changed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When deploying your changes, the default option is deploy everything which also restarts all your flows. You can also select to deploy just the nodes you edited or just the flows in which any changes were made.&lt;/p&gt;
&lt;p&gt;This allows you to update part of your flow without restarting other sections. This can be really handy when you have different flows spread across your workspace or tabs but you don&#39;t want to reload them all each time you deploy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Deploying only the changed nodes&quot; alt=&quot;Deploying only the changed nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/deploy.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;2.-find-which-debug-node-generated-an-entry-in-the-log&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/#2.-find-which-debug-node-generated-an-entry-in-the-log&quot;&gt;2. Find which debug node generated an entry in the log&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your flow has a few debug nodes it can become challenging to see which particular node generated an entry in the log. To quickly track an entry back to its source, click the text &#39;node: debug&#39; and you will be whisked back to the specific debug node, even it it&#39;s elsewhere on you workspace or even on a different tab.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Finding the debug node which generated the log line&quot; alt=&quot;Finding the debug node which generated the log line&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/debug-jump.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;3.-the-delay-node-can-be-used-as-a-rate-limiter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/#3.-the-delay-node-can-be-used-as-a-rate-limiter&quot;&gt;3. The delay node can be used as a rate limiter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes it&#39;s useful to be able to limit messages to only allow one every so many minutes. You may for example send alerts when a temperature sensor goes above a particular threshold but you don&#39;t want your email or instant messaging inbox being swamped with repeated alerts for the same issue.&lt;/p&gt;
&lt;p&gt;You can use the delay node to limit how many messages can pass through in a given period of time.&lt;/p&gt;
&lt;p&gt;Open the delay node settings, select Rate Limit then select 1 message per 15 minutes, then select &#39;Drop intermediate messages&#39;. This flow will now output a maximum of one message every quarter of an hour, all others will be deleted.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Limiting how many alerts are sent&quot; alt=&quot;Limiting how many alerts are sent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/rate-limit.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enhance-efficiency-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-2/#enhance-efficiency-with-flowfuse&quot;&gt;Enhance Efficiency with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse is a cloud-based platform designed to boost collaboration, security, and scalability for your Node-RED applications. It features &lt;a href=&quot;https://flowfuse.com/platform/features/&quot;&gt;numerous tools and functionalities&lt;/a&gt; that streamline the development-to-deployment process, including one-click deployment, the &lt;a href=&quot;https://flowfuse.com/docs/user/expert/&quot;&gt;FlowFuse Assistant&lt;/a&gt;, and other capabilities that simplify managing your Node-RED environment.&lt;/p&gt;
&lt;p&gt;For more tips, tricks, and professional development techniques with Node-RED, check out our recommended eBook:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;The Ultimate Beginner&#39;s Guide to Professional Node-RED&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/ming-blog/</id>
        <title>MING Stack for IoT</title>
        <summary>A technology stack for IoT</summary>
        <updated>2023-02-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/ming-blog/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The folks at Balena have created a bundle they call the &lt;a href=&quot;https://hub.balena.io/organizations/marc6/apps/MING&quot;&gt;MING stack&lt;/a&gt;, (Mosquitto/MQTT, InfluxDB, Node-RED and Grafana) which first appeared back in &lt;a href=&quot;https://forums.balena.io/t/ming-an-iot-sensor-stack-mosquitto-influxdb-nodered-grafana/36540&quot;&gt;2019&lt;/a&gt;. It is an interesting way to look at the IoT tech stack and a pattern I have seen used many times.&lt;/p&gt;
&lt;p&gt;In the early days of the web, the &lt;a href=&quot;https://en.wikipedia.org/wiki/LAMP_(software_bundle)&quot;&gt;LAMP stack&lt;/a&gt; was popularized as being the open source tech stack for hosting web sites. First used in 1998, LAMP stood for Linux, Apache, MySQL and Python/Perl/PHP. The LAMP stack did a lot to popularize open source software and create architecture patterns for building web applications. The LAMP stack did a lot to simplify a confusing technology landscape back in the early days of the web.&lt;/p&gt;
&lt;p&gt;Can the IoT industry benefit from a MING stack? There is a fair amount of complexity building IoT systems. Therefore, having defined architecture patterns might help reduce some of the confusion. In fact, MING does bring together the key open source components of an IoT system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mosquitto.org/&quot;&gt;Mosquitto&lt;/a&gt; is the popular open source MQTT broker. MQTT has become the default protocol for IoT communications. The MQTT pub/sub protocol solves a lot for the communication challenges for IoT applications. In fact, I would define the M as being MQTT since there are a lot of MQTT broker implementations available.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.influxdata.com/&quot;&gt;InfluxDB&lt;/a&gt; is the popular open source time series database. Many IoT use cases are based on analyzing trends from different IoT devices. The classic examples is preventive maintenance of factory equipment. Having a time series database in your IoT architecture to record trending information will solve a lot of your data problems.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/node-red/&quot;&gt;Node-RED&lt;/a&gt; is the popular low-code development environment that helps create flows of data. IoT systems are often pulling data from many different sources. The data needs to be filtered, analysed or transformed before being forward to another service. Node-RED has a large community of data nodes that makes it easy to collect data from a wide variety of sources. For instance in the industrial world, Node-RED nodes are available for OPC-UA, Modbus, S7, MQTT, various PLC platforms like Opto22, etc, etc.&lt;/li&gt;
&lt;li&gt;Finally &lt;a href=&quot;https://grafana.com/&quot;&gt;Grafana&lt;/a&gt; is a popular open source visualization platform. Real time monitoring of IoT data is often the first applications deployed for IoT systems. Having graphing and dashboard technology available in your architecture makes perfect sense.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another important feature of MING is that it can be deployed on the edge or in the cloud. IoT systems are inheritenty distributed so having the same technology available at different tiers is useful for lower barriers to adoption.&lt;/p&gt;
&lt;p&gt;The LAMP stack was successful because it was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open source and freely available for anyone to adopt and use.&lt;/li&gt;
&lt;li&gt;Highly flexible and customizable that allowed developers to adopt the stack to their use case.&lt;/li&gt;
&lt;li&gt;Back by large developer communities creating plugins/extensions, documentation, tutorials, etc.&lt;/li&gt;
&lt;li&gt;Easy to learn for developers with limited experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The MING stack has all the same characteristics. All four technologies are open source, highly flexible, back by large developer communities and relatively easy to learn. There are a lot of similarities between MING and LAMP.&lt;/p&gt;
&lt;p&gt;Is MING relevant for IoT use cases? In my experience, people building IoT solutions are using 3-4 of the MING components. What is your experience?&lt;/p&gt;
&lt;h2 id=&quot;simplify-iot-complexity-with-flowfuse%E2%80%99s-mind-stack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/ming-blog/#simplify-iot-complexity-with-flowfuse%E2%80%99s-mind-stack&quot;&gt;Simplify IoT Complexity with FlowFuse’s MIND Stack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’re concerned about managing multiple components in your IoT stack, FlowFuse has you covered. By bundling three of the four core elements of the MING stack—MQTT, Node-RED, and Grafana. FlowFuse simplifies your setup and management. This streamlined approach means fewer moving parts and less complexity, allowing you to focus on what matters most: your data and your applications.&lt;/p&gt;
&lt;p&gt;With the FlowFuse &lt;a href=&quot;https://flowfuse.com/blog/2024/05/node-red-mind-stack-with-flowfuse/&quot;&gt;MIND stack&lt;/a&gt;, you get a unified platform that integrates MQTT for efficient communication, Node-RED for seamless integration and data transformation, and &lt;a href=&quot;https://flowfuse.com/platform/dashboard/&quot;&gt;Dashboard 2.0&lt;/a&gt; for powerful visualizations—all from one place. This integration reduces configuration and maintenance overhead while ensuring consistent performance and security across your deployments. Explore the MIND stack now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Want an easier, more secure, and scalable IoT stack? Start your &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free trial&lt;/a&gt; of FlowFuse today.&lt;/strong&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/</id>
        <title>FlowFuse v1.4 with device provisioning in bulk and staged development process</title>
        <summary>Our second release of 2023 with some great new features to try out.</summary>
        <updated>2023-02-16T14:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Deploy Node-RED to many devices quickly, and allow a staged development process with the latest release of FlowFuse v1.4.&lt;/p&gt;
&lt;p&gt;Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;To make it easy for everyone to experience FlowFuse, we are introducing a new free 30-day trial. You can now experience the power of using FlowFuse to quickly deliver Node-RED applications in a reliable, repeatable, collaborative, and secure manner. To get your free trial simply &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up for FlowFuse Cloud;&lt;/a&gt; no credit card is required!&lt;/p&gt;
&lt;h2 id=&quot;new-user-features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#new-user-features&quot;&gt;New User Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Automatic Device Provisioning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most prominently, FlowFuse 1.4 features automatic device onboarding for fleets. Simply download a FlowFuse device provisioning credential to allow quick roll-out to a whole fleet, without the need to have device specific configuration. When the agent starts, the FlowFuse agent and the Node-RED snapshot will automatically be provisioned to the device and start operations. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1212&quot;&gt;Issue #1212&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;lite-youtube videoid=&quot;XTVw4O4-Crg&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;
&lt;p&gt;&lt;strong&gt;Support for Staged Development&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A new feature of 1.4 is the ability to setup staged deployments. This makes it possible to simply move a project between a Development &amp;gt; Test &amp;gt; Production for your Node-RED application delivery. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1580&quot;&gt;Issue #1580&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;lite-youtube videoid=&quot;6QOmotlrwWw&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It&#39;s now much easier to change the resources available to your Node-RED instance. With a few clicks a resource intensive workload can be processed faster by changing between small, medium, or large instance types. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/595&quot;&gt;#595&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Last release allows users to capture flows in a shared library to reuse in another flow, now it&#39;s possible to preview the stored flows. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1657&quot;&gt;#1657&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a synchronous mode for the FlowFuse persisted context store, next to the asynchronous mode already available. &lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-persistent-context/issues/17&quot;&gt;#17&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a Last Seen status for devices connecting to FlowFuse. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1599&quot;&gt;#1599&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added a check to ensure the team slug is unique. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1609&quot;&gt;#1609&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optionally set snapshot as target at creation, to quickly roll out changes to remote deployments &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1527&quot;&gt;#1527&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agents are more rugged when starting up if they&#39;re unable to connect to FlowFuse, and will retry to connect.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With FlowFuse v1.4 some changes were made under the hood to speed up the recovery
of Node-RED instances. On terminal failures of an instance it will now be
automatically be redeployed with the correct flows. This uses Kubernetes features
and is also available if you&#39;ve installed through &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;kubernetes&lt;/a&gt;.
To migrate the old style of deployments to this system a restart or stack upgrade is needed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deleting your only team, doesn&#39;t exit from the team UI. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1630&quot;&gt;#1630&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Async Team Slug Check. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1609&quot;&gt;#1609&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve communication of Device Last Seen and Status &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1599&quot;&gt;#1599&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/UlisesGascon&quot;&gt;UlisesGascon&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/installer/pull/74&quot;&gt;#74&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building.
If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.4.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/flowforge-1-4-0-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That&#39;s also a great place to send us any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;You can also get help on &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;the Node-RED forums&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As well as in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/discussions&quot;&gt;forum within our Github project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/highly-available-node-red/</id>
        <title>Toward Highly Available Node-RED</title>
        <summary>How mission critical use-cases can be supported through FlowFuse soon</summary>
        <updated>2023-02-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/highly-available-node-red/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Over the past few months we&#39;ve held a lot of product discovery sessions and a topic
which keeps coming up is &amp;quot;HA Node-RED&amp;quot;. All software will have failures, with
HA (high availability) the intent is to allow the workload to be processed
regardless. There&#39;s quite a few considerations which are often not covered
during product discovery calls, I&#39;m going to discuss some of those points in this article.&lt;/p&gt;
&lt;p&gt;When my job title was software engineer I was fortunate to design and
implement a HA system. It&#39;s an incredibly challenging and rewarding task for
any software engineer. As a topic, it&#39;s studied when obtaining a Computer Science
Bachelors degree, masters and even PhD. When tasked
to make a HA system, it took me a good month to define what our goals
were, and what we were willing to exchange for the properties sought. This
might be extra hardware, engineering hours, as well as organizational challenges.
For now, let&#39;s focus on the first two.&lt;/p&gt;
&lt;p&gt;Let&#39;s start with defining the goal; reduce the impact of a Node-RED instance
being unresponsive for an arbitrary reason. In many use-cases the MTTR (Mean Time To
Recovery) is what&#39;s measured. When for example a hardware failure takes down the instance and the time to
detection is zero, it will likely still take a few hours to recover. Most of
the recovery work is also manual, and knowledge on how to recover is usually
&lt;a href=&quot;https://en.wikipedia.org/wiki/Tribal_knowledge&quot;&gt;tribal knowledge&lt;/a&gt;. If the right
person is on-site, the right hardware is available, you kept great backups,
and are able to deploy the new hardware right away without support from other
functions you might just achieve an MTTR of 120 minutes!&lt;/p&gt;
&lt;h3 id=&quot;5-10-minute-mean-time-to-recovery&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/#5-10-minute-mean-time-to-recovery&quot;&gt;5-10 minute Mean Time to Recovery&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What&#39;s needed to bring this back to say 10 minutes? First, adopting FlowFuse will
help massively here. FlowFuse can be installed on-premise, or you can use our
managed Cloud offering. The software is the same, provided the on-premise
install uses our &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes install&lt;/a&gt; method.&lt;/p&gt;
&lt;p&gt;The key of the installation is the fact that the hardware layer is generalized
as a fleet. Detecting failures is included in the install, and very fast. Comparing
that to most alerting systems currently, it&#39;s usually a difference between night
and day. Furthermore, to decrease the recovery time significantly
there&#39;s a requirement to make software responsible for the whole procedure. Human intervention is much too slow.&lt;/p&gt;
&lt;p&gt;To get the MTTR down to 5 minutes there&#39;s a requirement to either make hardware
automatically available to the fleet, or to over-provision (more hardware is
available than is needed at any given moment). When a hardware failure occurs
FlowFuse is configured to ensure all Node-RED instances that are KIA are
replaced. Bringing down the time to recovery to about 5 minutes.
For many use-cases a MTTR of 5 minutes is &lt;em&gt;good enough&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;sub-minute-mttr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/#sub-minute-mttr&quot;&gt;Sub minute MTTR&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To go below the minute, or dare I say go below 10 seconds, we&#39;ll need to increase
the number of running Node-RED instances. Let&#39;s start with a hot-spare. Meaning
there&#39;s a running Node-RED instance with the flows exactly the same as another,
ready to pick up the work when the first has some failure. Note this isn&#39;t like
a relay race, there&#39;s no baton being passed from one Node-RED to the other. While
some data and messages might be lost, it&#39;s possible to redirect all workload from
the plagued Node-RED to the hot-spare in a matter of seconds. Hot-spares taking
over are usually only observed by humans a good few minutes after they replace a failed instance.&lt;/p&gt;
&lt;h3 id=&quot;sub-second!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/#sub-second!&quot;&gt;Sub second!&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before this post turns into a theoretical exercise we&#39;d really need to understand
which trade-offs are acceptable to you. There&#39;s the &lt;a href=&quot;https://en.wikipedia.org/wiki/CAP_theorem&quot;&gt;CAP Theorem&lt;/a&gt;
which states 3 guarantees are wanted: Consistency, Availability, and Partition Tolerance. You get to pick
only two. In manufacturing the line must never be stopped due to a software failure where possible,
so Availability is the most important. The question is, what comes next? Is it Consistency meaning
all 3 instances have the same view of the global state? Or maybe Partition Tolerance where it&#39;s vital for each instance need to be able to predict the intended action even if it can&#39;t communicate to the others?&lt;/p&gt;
&lt;p&gt;Whichever 2 you choose will dictate engineering choices in the pursuit of a great HA solution.&lt;/p&gt;
&lt;h3 id=&quot;the-roadmap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/highly-available-node-red/#the-roadmap&quot;&gt;The roadmap&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With FlowFuse v1.4, released February 2023, a 5 minute mean time to recovery is
achieved for all flows running locally, that is: in the cluster. Going beyond this
milestone requires your input! I&#39;d love to chat about your challenges, please
&lt;a href=&quot;https://meetings-eu1.hubspot.com/zeger-jan&quot;&gt;pick a timeslot to discuss your requirements&lt;/a&gt;!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/</id>
        <title>Service Disruption Report for January 27th, 2023</title>
        <summary></summary>
        <updated>2023-02-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;On January 27th, 2023, we were alerted to an issue on FlowFuse Cloud where a user
was not able to access a newly created Node-RED Project, receiving a 404 error
instead. This post examines the issue that was hit, the timeline of events and
what we&#39;ve done to resolve it.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We hit a limit in the AWS Load Balancer that capped how many projects could be
exposed to the internet within our FlowFuse Cloud deployment. The result of this
was that users could create a new Node-RED project, but they would not be able
to access the editor.&lt;/p&gt;
&lt;p&gt;We freed up capacity on the platform to allow user projects to be created without
hitting the limit, whilst also asking AWS to increase the limit in question which
they duly did.&lt;/p&gt;
&lt;p&gt;However, we later discovered a second limit that was also being applied. That limit
was not one AWS permits us to change.&lt;/p&gt;
&lt;p&gt;We successfully completely deployment of a change to our platform architecture
today that removes these limits from our environment.&lt;/p&gt;
&lt;p&gt;In total, this lead to approximately 2 hours of disruptions on January 27th 2023 and again
on February 8th 2023 during which newly created Node-RED projects were not accessible.&lt;/p&gt;
&lt;p&gt;Our logs show that two users were impacted during these times.&lt;/p&gt;
&lt;h2 id=&quot;technical-details&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/#technical-details&quot;&gt;Technical Details&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When running FlowFuse within a Kubernetes environment, each project creates a
new Ingress Object configuration to tell the platform how to route HTTP traffic
to that project.&lt;/p&gt;
&lt;p&gt;Our FlowFuse Cloud deployment runs within Amazon Elastic Kubernetes Service (EKS)
and uses the Application Load Balancer (ALB) service as its ingress controller.&lt;/p&gt;
&lt;p&gt;When the FlowFuse platform creates the new Ingress Object configuration, EKS passes
that to ALB to generate the necessary configuration, which, given the configuration we
were using, created both a Target Group and Rule object.&lt;/p&gt;
&lt;p&gt;With a default of limit of 100 Target Groups and Rules, that meant we had a technical
limit of 100 Node-RED projects within the FlowFuse Cloud environment. Increasing
the Rule limit did not solve the problem as the Target Group limit still applied.&lt;/p&gt;
&lt;p&gt;Our initial mitigation was to delete any Node-RED projects we had created for
our own internal testing. We also identified that we could safely delete any rules
for suspended projects. A suspended project is one that is not actively running
in the platform. The code that resumes a suspended project would recreate any ingress
objects needed - so deleting the rule whilst suspended would not have any impact
on the project.&lt;/p&gt;
&lt;p&gt;This gave us a small amount of headroom on the platform which crucially meant we
had time to develop a longer term solution.&lt;/p&gt;
&lt;h2 id=&quot;resolution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/#resolution&quot;&gt;Resolution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There were two possible routes we could take to resolve this issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Investigate how to reuse existing Target Groups rather than create one for each project&lt;/p&gt;
&lt;p&gt;Our intial research was inconclusive on how to achieve this. The AWS docs weren&#39;t
clear enough to give us a definitive answer we felt comfortable to invest our time
in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move away from ALB in favour of nginx to provide our ingress load balancing.&lt;/p&gt;
&lt;p&gt;This was always our long term strategy as it was a prerequisite to FlowFuse
features we have in the roadmap such as providing custom domains to projects.
However it was potentially a large piece of work with a complicated migration
for the existing environment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given it fitted with our longer-term strategic goals, we decided to move ahead
with replacing ALB with nginx.&lt;/p&gt;
&lt;p&gt;After some initial development work and experimentation, we felt comfortable that
the migration was not as complicated as initially feared. We would have to manually
copy the existing ALB rules over - something that could be scripted. Once we had
nginx deployed we could push a small code change to FlowFuse to use it rather than
ALB, and also switch over the DNS entry to point at nginx.&lt;/p&gt;
&lt;p&gt;Following a successful run through in our testing/staging environment, we decided
to move ahead updating the production environment.&lt;/p&gt;
&lt;p&gt;This change was applied today, whilst we closely monitored the system to ensure
no further disruption occurred. We have validated that new projects can be
created without issue and everything is working as it should.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With FlowFuse Cloud updated to use the new load balancer, we&#39;ll be closely monitoring
it over the next few days to ensure it operates normally.&lt;/p&gt;
&lt;p&gt;We will also be taking on some follow-up activities to minimise the risk of this
type of issue happening again:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review all AWS limits within our architecture. Identify any that pose a potential
issue in the future. Ensure they are documented and a plan put in place to mitigate
the impact based on our expected platform growth.&lt;/li&gt;
&lt;li&gt;Add additional external monitoring for project liveness.&lt;/li&gt;
&lt;li&gt;Review all logging around k8s apis&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;timeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/service-disruption-report-2023-01-27/#timeline&quot;&gt;Timeline&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;All times are GMT.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-27 22:15&lt;/strong&gt; : (Friday evening) Customer reports via our support channel a newly created project was not accessible and returning a 404 error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-27 22:22&lt;/strong&gt; : We start examining the platform logs&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-27 22:47&lt;/strong&gt; : We identify we&#39;ve hit the default Rules limit on the AWS Application Load Balancer&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-27 23:15&lt;/strong&gt; : To free-up capacity on the platform we delete any ununsed internal projects we were using for general testing. We also identify we can safely delete any rules associated with suspended projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-27 23:41&lt;/strong&gt; : We complete deleting rules to give us enough head-room to see us through the weekend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-01-30 10:00&lt;/strong&gt; : We submit a request to AWS to increase the rule limit to 200 which is accepted and actioned later that day.&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-02-08 14:05&lt;/strong&gt; : Another customer reports seeing a newly created project returning a 404 error. We examine the ALB configuration and whilst it reports the new limit has been changed to 200, it appears to still be limiting at 100. We start identifing more suspended projects we can delete the rules for to free up capacity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-02-08 14:20&lt;/strong&gt; : Sufficient capacity is freed to enable the customer&#39;s projects to be accessible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-02-08 15:00&lt;/strong&gt; : We identify we&#39;ve hit the ALB Target Group limit. This is a hard limit that AWS does not allow you to change. We begin researching options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-02-09&lt;/strong&gt; : Commited to plan to replace ALB with nginx. Successful migration of our staging environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2023-02-10&lt;/strong&gt; : Change applied to production, FlowFuse 1.3.3 deployed and DNS updated to use the new load balancer.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/</id>
        <title>Node-RED Tips - Wiring Shortcuts</title>
        <summary>Save yourself time when working on Node-RED with these three tips.</summary>
        <updated>2023-02-07T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;There is usually more than one way to complete a given task in software and Node-RED is no exception. In this blog post we are going to share three useful tips to save yourself time when working on your flows.&lt;/p&gt;
&lt;h3 id=&quot;1.-use-control%2Bleft-click-to-search-your-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/#1.-use-control%2Bleft-click-to-search-your-nodes&quot;&gt;1. Use control+left-click to search your nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes it&#39;s quicker to search for a node using its name rather than scrolling through the palette. Simply hold control then left-click to bring up a searchable list.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Selecting a node without having to use the palette&quot; alt=&quot;Selecting a node without having to use the palette&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/load-node.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;2.-split-sections-of-your-code-using-the-link-nodes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/#2.-split-sections-of-your-code-using-the-link-nodes&quot;&gt;2. Split sections of your code using the link nodes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to separate your flow into two distinct sections, link nodes are a great way to format your work. As we covered in our blog on &lt;a href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/&quot;&gt;Node-RED best practices&lt;/a&gt;, the combination of link nodes and grouped flows is very powerful.&lt;/p&gt;
&lt;p&gt;To split your flow select the input and output nodes then right click, select &#39;Show Action List&#39; and then type &#39;split&#39;. Select &#39;Split wire with link nodes&#39;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Spliting your nodes with link nodes&quot; alt=&quot;Spliting your nodes with link nodes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/split-with-link.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;3.-link-multiple-inputs-and-outputs-in-one-command&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/3-quick-node-red-tips-1/#3.-link-multiple-inputs-and-outputs-in-one-command&quot;&gt;3. Link multiple inputs and outputs in one command&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once a switch node has several outputs it can be slow to manually wire each to the new node. Using the action menu (right click), select &#39;Show Action List&#39; then &#39;Wire Node to Multiple&#39; this option will join everything up in one step.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Linking multiple inputs and outputs in one command&quot; alt=&quot;&amp;quot;Linking multiple inputs and outputs in one command&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/join-wires.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;We hope you found these tips useful, if you&#39;d like to suggest some of your own tips which you think we should share in our future blog posts please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/02/community-news-02/</id>
        <title>Community News February 2023</title>
        <summary>Your monthly update for the FlowFuse and Node-RED communities</summary>
        <updated>2023-02-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/02/community-news-02/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for February 2023, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;p&gt;If you&#39;ve got something that you think we should share on our newsletters please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;news&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#news&quot;&gt;News&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;node-red-ask-me-anything&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#node-red-ask-me-anything&quot;&gt;&lt;a href=&quot;https://flowfuse.com/ask-me-anything/ama-nodered/&quot;&gt;Node-RED Ask Me Anything&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;AMA Session with Nick O&#39;Leary and Rob Marcer&quot; alt=&quot;AMA Session with Nick O&#39;Leary and Rob Marcer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ama-feb.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Do you have any questions about Node-RED or need some advice on a tricky issue using Node-RED? Here is your opportunity to get help from the experts.&lt;/p&gt;
&lt;p&gt;Nick O&#39;Leary, co-founder of Node-RED &amp;amp; CTO of FlowFuse, and Rob Marcer, Node-RED community member &amp;amp; Developer Educator at FlowFuse, will be hosting an interactive Ask Me Anything session. This is a great opportunity to ask questions of the Node-RED experts. If you have any questions for Nick and Rob you can send them in before the session using &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSdfPq4lAQjdvqhTpoYtKiMNgP8vcMhZsAf_AG0MHuVMRK83_Q/viewform&quot;&gt;this form&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;free-flowfuse-project-for-30-days%2C-no-catches&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#free-flowfuse-project-for-30-days%2C-no-catches&quot;&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Free FlowFuse project for 30 days, no catches&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make it easy for everyone to experience FlowFuse, we are introducing a new &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free 30-day trial&lt;/a&gt;. With this trial, you can experience the power of using FlowFuse to quickly deliver Node-RED applications in a reliable, repeatable, collaborative, and secure manner. To get your trial simply &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up for a new FlowFuse team&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;1.3-released&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#1.3-released&quot;&gt;&lt;a href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/&quot;&gt;1.3 Released&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Version 1.3 of FlowFuse was released on 19th January. Our first release of 2023 included some great new features such as the ability to share flows via a &lt;a href=&quot;https://www.youtube.com/watch?v=B7XK3TUklUU&quot;&gt;team library&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=JRk-Cf7eNIo&quot;&gt;control access to your Node-RED dashboards&lt;/a&gt; using FlowFuse credentials, and &lt;a href=&quot;https://www.youtube.com/watch?v=p0Vuy5x42Go&quot;&gt;filtering on your audit logs&lt;/a&gt; for easier reading. We also added the ability to use FlowFuse on devices which cannot access npm, we think this will be really valuable to users of networks with limited access to the internet.&lt;/p&gt;
&lt;p&gt;We&#39;re now working towards release 1.4 which is due on 16th February. You can see what we are planning to deliver in that release and beyond on &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;FlowFuse&#39;s project board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 1.3 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/&quot;&gt;blog post&lt;/a&gt;, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v1.3.0&quot;&gt;GitHub release page&lt;/a&gt;, and &lt;a href=&quot;https://www.youtube.com/watch?v=ey3xv5j5x7k&quot;&gt;Youtube channel&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;team-news&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#team-news&quot;&gt;&lt;a href=&quot;https://flowfuse.com/team/&quot;&gt;Team News&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We are currently recruiting &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004&quot;&gt;NodeJS Developers&lt;/a&gt; as well as a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4785058004&quot;&gt;Graphic Designer&lt;/a&gt; to join our team. You can view any of the roles we currently have open and apply on our &lt;a href=&quot;https://boards.greenhouse.io/flowfuse&quot;&gt;Jobs page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;node-red-in-the-community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#node-red-in-the-community&quot;&gt;Node-RED in the Community&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;twitch-streamer-beats-elden-ring-boss-using-mind-control-(and-a-little-node-red)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#twitch-streamer-beats-elden-ring-boss-using-mind-control-(and-a-little-node-red)&quot;&gt;&lt;a href=&quot;https://www.vice.com/en/article/bvmqmm/watch-an-elden-ring-streamer-beat-a-boss-using-her-thoughts&quot;&gt;Twitch Streamer beats Elden Ring boss using mind control (and a little Node-RED)&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.vice.com/en/article/bvmqmm/watch-an-elden-ring-streamer-beat-a-boss-using-her-thoughts&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Twitch Streamer beats Elden Ring boss using mind control (and a little Node-RED)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/twitch.webp&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/a&gt;
Streamer &lt;a href=&quot;https://www.twitch.tv/videos/1717013810&quot;&gt;Perrikaryal&lt;/a&gt; used an electroencephalography (EEG) headset to read her brain activity which in turn sends commands via Node-RED to her gaming computer. She then proceeded to use that control method to beat one of the harder bosses in Elden Ring, a notoriously difficult game to start with. The end result is a great example of how Node-RED can link disparate tech together easily. You can &lt;a href=&quot;https://www.twitch.tv/videos/1722048787&quot;&gt;watch the full stream on Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;run-node-red-in-a-web-browser%2C-client-side!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#run-node-red-in-a-web-browser%2C-client-side!&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/posts/kazuhitoyokoi_nodered-webassembly-activity-7015696090112958464-F3MA/?utm_source=share&amp;amp;utm_medium=member_android&quot;&gt;Run Node-RED in a web browser, client side!&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/kazuhitoyokoi/&quot;&gt;Kazuhito Yokoi&lt;/a&gt; has implemented an early prototype of Node-RED runtime for WebAssembly. As a demonstration, he built a simple flow which shows the current location of the International Space Station (ISS). This proof-of-concept shows that an entire Node-RED flow can be executed in a browser. We think this could be a very useful option for running Node-RED in places where it wasn’t previously practical. You can view his work on this &lt;a href=&quot;https://github.com/kazuhitoyokoi/node-red-wasm&quot;&gt;GitHub project&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;custom-node-spotlight---moment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/02/community-news-02/#custom-node-spotlight---moment&quot;&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-moment&quot;&gt;Custom Node Spotlight - Moment&lt;/a&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-moment&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Moment converting a timestamp to ISO standard date and time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/moment.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/a&gt;
Being able to easily switch dates and times from one format to another is a huge timesaver, node-red-contrib-moment makes those tasks a breeze. The package actually includes two custom nodes, the first ‘Moment’ produces a nicely formatted Date/Time string using the Moment.JS library. The second custom node ‘Humanizer’ converts time durations (time spans) into textual descriptions (e.g. 2 minutes). We recommend you keep it in mind for any flows working with time conversions.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/flowforge-story/</id>
        <title>Telling the FlowFuse Story</title>
        <summary>FlowFuse helps organizations reliably deliver Node-RED applications</summary>
        <updated>2023-02-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/flowforge-story/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;During my first month at FlowFuse, I have been helping to refine the FlowFuse story. Trying to answer the questions: What is the value FlowFuse brings to our customers and what features does FlowFuse want to offer the Node-RED community?&lt;/p&gt;
&lt;p&gt;People love Node-RED because it makes it trivial to connect different types of services and data, create flows of the data, and store/forward data to the cloud or a database. The Node-RED &lt;a href=&quot;https://flows.nodered.org/&quot;&gt;library of nodes and flows&lt;/a&gt; enables connections to almost anything. The speed and ease of use of Node-RED allows non-traditional programmers to accelerate their innovation and exploration of what is possible.&lt;/p&gt;
&lt;p&gt;Node-RED is great for individuals to unlock what is possible for an organization. However, there are some challenges if you want to scale Node-RED into a corporate development platform. Challenges like how do you set up a development -&amp;gt; test -&amp;gt; production delivery pipeline, how to share instances with different developers, how do you create repeatable release processes, how can you deploy the same Node-RED instance out to multiple target environments (devices or servers).&lt;/p&gt;
&lt;p&gt;Today, we see many industrial engineers using Node-RED to collect and integrate data from different factory and industrial equipment. Many PLC vendors, like Opto22, are enabling this by making Node-RED as a development environment for the PLC platform. In the manufacturing and industrial automation industries, benefits like reliability and security are important for the continuous operation of these facilities.  This is why we believe these types of organizations will be looking for tools that improve their software development lifecycle.&lt;/p&gt;
&lt;p&gt;In the larger software development community, DevOps tools are being used to address many of these same challenges. DevOps is all about increasing the reliability and speed of the software development lifecycle. Using tools that increase automation of the software development process and improve collaboration and communication between developers. These are also many of the same challenges that FlowFuse solves for Node-RED users.&lt;/p&gt;
&lt;p&gt;For these reasons, we see FlowFuse as being the DevOps platform for Node-RED. We believe FlowFuse enables a more reliable way to deliver Node-RED applications in a repeatable, collaborative and secure manner. What FlowFuse adds to Node-RED are some key features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tools for collaborative Node-RED development&lt;/li&gt;
&lt;li&gt;The ability to manage remote deployments of Node-RED instances&lt;/li&gt;
&lt;li&gt;A more streamline way to deliver Node-RED applications&lt;/li&gt;
&lt;li&gt;FlowFuse Cloud provides a hosted Node-RED platform but FlowFuse can also be self-hosted&lt;/li&gt;
&lt;li&gt;FlowFuse also offers professional technical support to organizations that require the assurance of receiving help with production deployments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will be rolling out this new way of talking about FlowFuse over the next couple of days and weeks. We are always open to feedback about FlowFuse and would love to hear about your experience of using Node-RED.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/</id>
        <title>Using Environment Variables in Node-RED</title>
        <summary>Predefined data to be used in your Node-RED instance</summary>
        <updated>2023-01-27T16:11:47Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Programs, written with Node-RED or otherwise, need to sometimes retrieve information that wasn’t decided on during the creation of the program.&lt;/p&gt;
&lt;p&gt;Contextual data like configuration, which user is executing the code, differentiate based on what device is executing a flow, or sometimes secrets which shouldn’t be exposed in the code. This is usually done through environment variables. These are pairs of strings, a key with an attached value, which are accessed by their key. Say you want to access an API endpoint with a key, you’d save the key as &lt;code&gt;API_KEY&lt;/code&gt; with the value set to &lt;code&gt;yoursupersecretkey&lt;/code&gt;. FlowFuse allows setting environment variables. Let’s start using them to understand how they work.&lt;/p&gt;
&lt;p&gt;One of the options for the &lt;code&gt;inject&lt;/code&gt; node is to inject a &lt;code&gt;env variable&lt;/code&gt;, short for; you guessed it: Environment Variable. In this case we’re going to one that’s pre-defined by Node-RED: &lt;code&gt;NR_FLOW_NAME&lt;/code&gt;. The name of each variable is in all caps by convention. When connecting this inject to a debug it prints “Flow 1” for me.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Using an environment variable in Node-RED&quot; alt=&quot;Using an environment variable in Node-RED&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/node-red-use-env-var.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Leveraging environment variables can also be done with other nodes, like for example &lt;code&gt;change&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;. Note however; you can set the &lt;code&gt;inject&lt;/code&gt; node to output the value for &lt;code&gt;FOO&lt;/code&gt; even when it doesn’t exist, but it doesn’t allow you to check in the switch node for example if &lt;code&gt;FOO&lt;/code&gt; exists.&lt;/p&gt;
&lt;p&gt;Node-RED allows you to set environment variables, but not to change them when executing flows. If you want to update data during execution, look into using &lt;a href=&quot;https://flowfuse.com/docs/user/persistent-context/&quot;&gt;persistent context&lt;/a&gt;. Node-RED doesn’t support Environment Variables like other programming environments do. When the flow is deployed the environment variables are replaced with the known values at that time. This is the biggest gotcha for most developers.&lt;/p&gt;
&lt;h3 id=&quot;predefined-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/#predefined-variables&quot;&gt;Predefined variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our first example was using a predefined variable, exposed by Node-RED. As of 3.0 it exposes a few environment variables among which &lt;code&gt;NR_NODE_NAME&lt;/code&gt;, &lt;code&gt;NR_GROUP_NAME&lt;/code&gt;, and &lt;code&gt;NR_FLOW_NAME&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; extends this list with for example a &lt;code&gt;FF_PROJECT_ID&lt;/code&gt; allowing you to for example understand what group of instances sent a certain message, but also sets them for each &lt;a href=&quot;https://flowfuse.com/docs/device-agent/introduction/&quot;&gt;device agent&lt;/a&gt;. This allows users to pinpoint which device sent a message, for example to update a dashboard accordingly.&lt;/p&gt;
&lt;h3 id=&quot;managing-environments-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/#managing-environments-variables&quot;&gt;Managing environments variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In FlowFuse it’s easy to manage variables set for instances. Under settings in the environment tab it’s a form to set them. You’ll have to restart your instances to make them available in the cloud, and update the target snapshot for devices. When done, these are available.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Setting a environment variable in FlowFuse&quot; alt=&quot;&amp;quot;Setting a environment variable in FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowforge-set-env-var.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;boost-your-node-red-security-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/#boost-your-node-red-security-with-flowfuse&quot;&gt;Boost Your Node-RED Security with FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FlowFuse provides a comprehensive platform for managing and securing your Node-RED solutions. It includes advanced security features such as role-based access control, Multi-factor Authentication (MFA), Single Sign-On (SSO), and encryption to protect your data and enhance operational efficiency.&lt;/p&gt;
&lt;p&gt;Learn how FlowFuse can boost your Node-RED security and streamline management through the &lt;a href=&quot;https://flowfuse.com/platform/security/#application&quot;&gt;FlowFuse security statement&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;explore-more-on-security&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/environment-variables-in-node-red/#explore-more-on-security&quot;&gt;Explore More on Security&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/04/role-based-access-control-rbac-for-node-red-with-flowfuse/&quot;&gt;Role-Based Access Control (RBAC) for Node-RED with FlowFuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/devops-pipelines/#protected-instances&quot;&gt;Protecting Instances from Being Modified&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-ldap-for-the-node-red/&quot;&gt;How to Set Up SSO LDAP for Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/07/how-to-setup-sso-saml-for-the-node-red/&quot;&gt;How to Set Up SSO SAML for Node-RED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/03/http-authentication-node-red-with-flowfuse/&quot;&gt;Securing HTTP Traffic for Node-RED with FlowFuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/blog/2024/01/soc2/&quot;&gt;FlowFuse is now SOC 2 Type 1 Compliant&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/getting-started-with-node-red/</id>
        <title>Getting Started with Node-RED</title>
        <summary>Node-RED is one of the easiest ways to program ever created but everyone needs a little help</summary>
        <updated>2023-01-23T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/getting-started-with-node-red/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Node-RED is a visual programming tool for working with IoT devices and web services. It allows users to create flows using a drag-and-drop interface, making it easy to connect different nodes together to build powerful automations.&lt;/p&gt;
&lt;p&gt;In this blog post, we&#39;ll take a look at how to get started with Node-RED and create some basic flows. We&#39;ll also explore the palette manager, a powerful feature that allows users to install and manage additional nodes for Node-RED.&lt;/p&gt;
&lt;h3 id=&quot;installing-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#installing-node-red&quot;&gt;Installing Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, you&#39;ll need to get an installation of Node-RED up and running. There are several ways to do this. We suggest using FlowFuse as it&#39;s very easy to get Node-RED running. You can also install Node-RED locally using npm (Node Package Manager), which comes with Node.js.&lt;/p&gt;
&lt;h4 id=&quot;flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#flowfuse&quot;&gt;FlowFuse&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To get Node-RED running on FlowFuse &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up as a new user&lt;/a&gt;. New users are enrolled in a trial and a Node-RED instance will be started for you within a minute.&lt;/p&gt;
&lt;p&gt;Once that instance has booted up you can access Node-RED by pressing &amp;quot;Open Editor&amp;quot;.&lt;/p&gt;
&lt;h4 id=&quot;npm&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#npm&quot;&gt;npm&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To install Node-RED locally using npm, open up your terminal and type the following command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-27&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-27&quot; class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; node-red&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-27&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Once Node-RED is installed, you can start it by running the following command:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-31&quot;&gt;
  &lt;pre class=&quot;language-bash&quot;&gt;&lt;code id=&quot;code-31&quot; class=&quot;language-bash&quot;&gt;node-red&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-31&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;This will start the Node-RED server and open up the &lt;a href=&quot;http://localhost:1880/&quot;&gt;editor in your web browser&lt;/a&gt;. You can also specify a different port or a settings file if you want to. If you want to run Node-RED locally but manage it remotely through FlowFuse, check out &lt;a href=&quot;https://flowfuse.com/blog/2025/09/installing-node-red/&quot;&gt;this guide&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;first-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#first-flow&quot;&gt;First Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you have Node-RED running, let&#39;s take a look at how to create a simple flow. In this example, we&#39;ll create a simple &amp;quot;Hello World&amp;quot; endpoint. To do this, we&#39;ll use the &lt;code&gt;http in&lt;/code&gt;, &lt;code&gt;http response&lt;/code&gt;, and the &lt;code&gt;change&lt;/code&gt; nodes, which can be found in the common nodes menu on the left of Node-RED.&lt;/p&gt;
&lt;p&gt;First, drag an &lt;code&gt;http in&lt;/code&gt; node into the editor. This node will listen for incoming HTTP requests. Next drag in the &amp;quot;change&amp;quot; and the &lt;code&gt;http response&lt;/code&gt; node into the editor. Connect the &lt;code&gt;http in&lt;/code&gt; node to the &lt;code&gt;change&lt;/code&gt; node and connect the &lt;code&gt;change&lt;/code&gt; node to the &lt;code&gt;http response&lt;/code&gt; node. Your flow should look similar to this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the HTTP-in, Change, and HTTP-response nodes that we will be using throughout this blog for demonstration.&quot; alt=&quot;&amp;quot;Screenshot showing the HTTP-in, Change, and HTTP-response nodes that we will be using throughout this blog for demonstration.&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/three-nodes.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To configure the &lt;code&gt;http in&lt;/code&gt; node, double-click on it to open its properties. Here, you can set the URL that the node will listen to, as well as the method (GET, POST, etc.). In this example, we&#39;ll set the URL to &lt;code&gt;/hello&lt;/code&gt; and the method to &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we need to set what the endpoint will respond with, we will do that in the &lt;code&gt;change&lt;/code&gt; node. Double-click the &lt;code&gt;change&lt;/code&gt; node then add &amp;quot;Hello World&amp;quot; to the field which says &amp;quot;to the value&amp;quot;. It should look like this:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Configuring the change node to set the payload to Hello World&quot; alt=&quot;&amp;quot;Configuring the change node to set the payload to Hello World&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/set-reply.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To configure the &lt;code&gt;http response&lt;/code&gt; node, double-click on it to open its properties. Here, you should set the &amp;quot;Status Code&amp;quot; to be 200. This is not vital for the demo to work but it&#39;s good practice to return the correct codes when something connects to an API. Status code 200 means the API responded OK. This is how your &lt;code&gt;http response&lt;/code&gt; node should look:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Configuring the status node to set the response to 200&quot; alt=&quot;&amp;quot;Configuring the status node to set the response to 200&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/response-code.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can read more about HTTP response codes in &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_HTTP_status_codes&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;testing-your-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#testing-your-flow&quot;&gt;Testing Your Flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have our flow set up, we can deploy it by clicking the &amp;quot;Deploy&amp;quot; button in the top right corner of the editor. Once the flow is deployed, you can test it by opening up a web browser. If you installed Node-RED using npm navigate to &amp;quot;http://localhost:1880/hello&amp;quot;. If you are working on FlowFuse and running cloud hosted instance, use your instance URL with &amp;quot;/hello&amp;quot; added to the end, it should look something like &amp;quot;https://your-instance-name.flowfuse.cloud/hello&amp;quot;. You should see &amp;quot;Hello World!&amp;quot; displayed in the browser.&lt;/p&gt;
&lt;h3 id=&quot;debug-output&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#debug-output&quot;&gt;Debug Output&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the most powerful features in Node-RED is the ability to debug your flow. This can be done by adding a debug node to your flow and connecting it to the nodes you want to debug. When a message is sent through the connected node, the debug node will print the message in the debug sidebar on the right side of the editor. This can be very helpful when trying to understand how a flow is working or troubleshoot any issues.&lt;/p&gt;
&lt;h3 id=&quot;the-palette-manager&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#the-palette-manager&quot;&gt;The Palette Manager&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to the built-in nodes, Node-RED also has a palette manager feature which allows users to easily install and manage additional nodes from the community. To access the palette manager, go to the menu in the top right corner and select &amp;quot;Manage Palette&amp;quot;. Here, you can search for and install new nodes, as well as update or remove existing ones. This is a great way to extend the functionality of Node-RED and add new capabilities to your flows.&lt;/p&gt;
&lt;h3 id=&quot;import-the-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#import-the-flow&quot;&gt;Import the flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to view this flow you can import it using the code below. Copy the code then select Import from the top right menu in Node-RED. Paste the code into the field then press Import.&lt;/p&gt;
&lt;div id=&quot;nr-flow-152&quot; style=&quot;height: 200px&quot; data-grid-lines=&quot;true&quot; data-zoom=&quot;true&quot; data-images=&quot;true&quot; data-link-lines=&quot;false&quot; data-labels=&quot;true&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;module&quot;&gt;const flow152 = &quot;&#92;n[&#92;n    {&#92;n        &#92;&quot;id&#92;&quot;: &#92;&quot;a742e7a95697bb40&#92;&quot;,&#92;n        &#92;&quot;type&#92;&quot;: &#92;&quot;http in&#92;&quot;,&#92;n        &#92;&quot;z&#92;&quot;: &#92;&quot;9e9af3caa4dc14d3&#92;&quot;,&#92;n        &#92;&quot;name&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;url&#92;&quot;: &#92;&quot;/hello&#92;&quot;,&#92;n        &#92;&quot;method&#92;&quot;: &#92;&quot;get&#92;&quot;,&#92;n        &#92;&quot;upload&#92;&quot;: false,&#92;n        &#92;&quot;swaggerDoc&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;x&#92;&quot;: 180,&#92;n        &#92;&quot;y&#92;&quot;: 200,&#92;n        &#92;&quot;wires&#92;&quot;: [&#92;n            [&#92;n                &#92;&quot;883e7d597f7c7c4b&#92;&quot;&#92;n            ]&#92;n        ]&#92;n    },&#92;n    {&#92;n        &#92;&quot;id&#92;&quot;: &#92;&quot;aca024dcb79bdb92&#92;&quot;,&#92;n        &#92;&quot;type&#92;&quot;: &#92;&quot;http response&#92;&quot;,&#92;n        &#92;&quot;z&#92;&quot;: &#92;&quot;9e9af3caa4dc14d3&#92;&quot;,&#92;n        &#92;&quot;name&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;statusCode&#92;&quot;: &#92;&quot;200&#92;&quot;,&#92;n        &#92;&quot;headers&#92;&quot;: {},&#92;n        &#92;&quot;x&#92;&quot;: 500,&#92;n        &#92;&quot;y&#92;&quot;: 200,&#92;n        &#92;&quot;wires&#92;&quot;: []&#92;n    },&#92;n    {&#92;n        &#92;&quot;id&#92;&quot;: &#92;&quot;883e7d597f7c7c4b&#92;&quot;,&#92;n        &#92;&quot;type&#92;&quot;: &#92;&quot;change&#92;&quot;,&#92;n        &#92;&quot;z&#92;&quot;: &#92;&quot;9e9af3caa4dc14d3&#92;&quot;,&#92;n        &#92;&quot;name&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;rules&#92;&quot;: [&#92;n            {&#92;n                &#92;&quot;t&#92;&quot;: &#92;&quot;set&#92;&quot;,&#92;n                &#92;&quot;p&#92;&quot;: &#92;&quot;payload&#92;&quot;,&#92;n                &#92;&quot;pt&#92;&quot;: &#92;&quot;msg&#92;&quot;,&#92;n                &#92;&quot;to&#92;&quot;: &#92;&quot;Hello World&#92;&quot;,&#92;n                &#92;&quot;tot&#92;&quot;: &#92;&quot;str&#92;&quot;&#92;n            }&#92;n        ],&#92;n        &#92;&quot;action&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;property&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;from&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;to&#92;&quot;: &#92;&quot;&#92;&quot;,&#92;n        &#92;&quot;reg&#92;&quot;: false,&#92;n        &#92;&quot;x&#92;&quot;: 340,&#92;n        &#92;&quot;y&#92;&quot;: 200,&#92;n        &#92;&quot;wires&#92;&quot;: [&#92;n            [&#92;n                &#92;&quot;aca024dcb79bdb92&#92;&quot;&#92;n            ]&#92;n        ]&#92;n    }&#92;n]&#92;n&quot;;
        new FlowRenderer().renderFlows(JSON.parse(flow152.replace(/&amp;gt;/g,&#39;&gt;&#39;).replace(/&amp;lt;/g,&#39;&lt;&#39;).replace(/&amp;amp;/g,&#39;&amp;&#39;)), { container: document.getElementById(&#39;nr-flow-152&#39;) })&lt;/script&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/getting-started-with-node-red/#what&#39;s-next%3F&quot;&gt;What&#39;s Next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Well done, you&#39;ve now got your first flow up and running. Enjoy using Node-RED and thanks for reading. Now if you want to start with your first beginner friendly project, building a weather dashboard is great, read this &lt;a href=&quot;https://flowfuse.com/blog/2025/12/getting-weather-data-in-node-red/&quot;&gt;article for getting started&lt;/a&gt;. If you&#39;d like to dive deeper into more Node-RED capabilities and how it can help in an enterprise setting, check out our &lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;eBook The Ultimate Beginner Guide to a Professional Node-RED&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/</id>
        <title>FlowFuse 1.3 is now available, share your flows through our new team libraries and much more</title>
        <summary>Our first release of 2023 with some great new features to try out, happy new year from everyone at FlowFuse!</summary>
        <updated>2023-01-19T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Share your flows via team libraries, control access to your Node-RED dashboards using FlowFuse credentials, and filter your audit logs by users and actions.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 1.3 is now available! Due to the recent holiday season, most of our team have been away from their desks but we still have some great new features to share. Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;To make it easy for everyone to experience FlowFuse, we are introducing a new &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;free 30-day trial&lt;/a&gt;. With this trial, you can experience the power of using FlowFuse to quickly deliver Node-RED applications in a reliable, repeatable, collaborative, and secure manner. To get your trial simply &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;sign up for a new FlowFuse team&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/237&quot;&gt;Share your flows via team libraries&lt;/a&gt; &lt;br /&gt;
FlowFuse has now added the ability for you to share your flows via the import and export features in Node-RED. Once you export a flow everyone else in your FlowFuse team will be able to import your work into their projects. You can see a demonstration of this new feature in &lt;a href=&quot;https://youtu.be/B7XK3TUklUU&quot;&gt;the video&lt;/a&gt; below.&lt;/p&gt;
&lt;div&gt;&lt;lite-youtube videoid=&quot;B7XK3TUklUU&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1325&quot;&gt;Control access to your Node-RED dashboards using FlowFuse credentials&lt;/a&gt; &lt;br /&gt;
In FlowFuse 0.10 we added the ability to secure endpoints created within your FlowFuse projects. This allows you to create dashboards or APIs and limit who can access them. In 1.3 we&#39;ve added the ability for you to limit access to those same resources based on the visitor having a user account on your FlowFuse team. You can see a demonstration of this new feature in &lt;a href=&quot;https://youtu.be/JRk-Cf7eNIo&quot;&gt;the video&lt;/a&gt; below.&lt;/p&gt;
&lt;div&gt;&lt;lite-youtube videoid=&quot;JRk-Cf7eNIo&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1448&quot;&gt;Filter your audit logs for easier reading&lt;/a&gt; &lt;br /&gt;
In FlowFuse 1.3 we’ve added the ability to filter your admin logs by user or action type. We think this is a great new feature which will help admins have confidence that they will be able to review the audit logs quickly when needed. You can see a demonstration of this new feature in &lt;a href=&quot;https://youtu.be/p0Vuy5x42Go&quot;&gt;the video&lt;/a&gt; below.&lt;/p&gt;
&lt;div&gt;&lt;lite-youtube videoid=&quot;p0Vuy5x42Go&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/45&quot;&gt;Allow installation of FlowFuse on devices which can&#39;t access npm&lt;/a&gt; &lt;br /&gt;
We&#39;ve had feedback from customers that in some cases they want to use FlowFuse devices on hardware which cannot access &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;Node Package Manager&lt;/a&gt; (npm). In a standard configuration of Node-RED, access to npm is mandatory to run your flows. In FlowFuse 1.3.0 we&#39;ve added the ability for you to import all the data usually installed from npm without your devices having access to the npm service.&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project status UI sometimes getting stuck when restarting &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1232&quot;&gt;#1232&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SSO users asked to click link in email to verify &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1543&quot;&gt;#1543&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SSO users unable to edit settings &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1542&quot;&gt;#1542&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SSO users not redirected to editor when signing in &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1481&quot;&gt;#1481&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like to thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/flecoufle&quot;&gt;flecoufle&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/helm/pull/89&quot;&gt;#89&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building.
If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install FlowFuse yourself via a variety of install options. You can find out more details &lt;a href=&quot;https://flowfuse.com/docs/install/introduction/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Get started for free&lt;/a&gt; on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.3.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1-3-0-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That&#39;s also a great place to send us any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;You can also get help on &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;the Node-RED forums&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AS well as in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/discussions&quot;&gt;forum within our Github project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/flowforge-1.2.1-released/</id>
        <title>FlowFuse 1.2.1 released</title>
        <summary>Release includes fix for emailing new user</summary>
        <updated>2023-01-12T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/flowforge-1.2.1-released/"/>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;We&#39;ve published a maintenance release containing a fix for new users.&lt;/p&gt;
&lt;p&gt;This release fixes an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1537&quot;&gt;issue&lt;/a&gt; introduced in FlowFuse 1.2 where users were not being sent their welcome email when they first sign up to the platform. As the sign-up page asks them to click on the link in that email, it left them waiting for an email that wasn&#39;t going to arrive.&lt;/p&gt;
&lt;p&gt;The same fix also addresses an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1514&quot;&gt;issue&lt;/a&gt; where users could not sign up using an email with a &lt;code&gt;+&lt;/code&gt; in it. This is a restriction we apply to users signing up with Single Sign-On enabled email domains - but the check was being applied to everyone.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1.2.1-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This release has already been rolled out to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2023/01/flowforge-1.2.1-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform, please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2023/01/community-news-12/</id>
        <title>Community News December 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2023-01-12T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2023/01/community-news-12/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for December 2022, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community. 2022 was a really exciting year for the development of both Node-RED and FlowFuse. Node-RED released version 3, another major milestone for the project. FlowFuse hit version 1, leaving the beta development stage. We are excited to see what the community can achieve in 2023!
If you&#39;ve got something that you think we should share on our newsletters please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get it touch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-red/node-red/milestone/19&quot;&gt;&lt;strong&gt;Node-RED Nears 3.1 Release&lt;/strong&gt;&lt;/a&gt;
The release of Node-RED 3.1 is expected very soon. 3.1 includes lots of great new features such as support for &lt;a href=&quot;https://github.com/node-red/node-red/pull/3938&quot;&gt;locking flows in the editor&lt;/a&gt; and &lt;a href=&quot;https://github.com/node-red/node-red/pull/3930&quot;&gt;improving the user experience around hiding flows&lt;/a&gt;. As an open source project the development of Node-RED is entirely dependent on individuals and companies giving their time to work towards each new release. If you&#39;d like to know how you can get involved you can read more on the &lt;a href=&quot;https://nodered.org/about/contribute/&quot;&gt;Node-RED web site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/&quot;&gt;&lt;strong&gt;FlowFuse 1.2 Released&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Version 1.2 of FlowFuse was released on 23rd December. Our last release of the year included some great new features such as &lt;a href=&quot;https://flowfuse.com/docs/cloud/introduction/#single-sign-on&quot;&gt;Single Sign-On&lt;/a&gt; to make it easier for your team to access your projects and &lt;a href=&quot;https://flowfuse.com/docs/cloud/introduction/#node-red-context&quot;&gt;Persistent Context&lt;/a&gt; which allows you to retain context values even when restarting projects. We&#39;re now working towards our first release of 2023 which is due on 19th January. You can see what we are planning to deliver in that release and beyond on &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;FlowFuse&#39;s project board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 1.2 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/&quot;&gt;blog post&lt;/a&gt;, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v1.2.0&quot;&gt;GitHub release page&lt;/a&gt;, and &lt;a href=&quot;https://www.youtube.com/watch?v=u7TjqUAub1g&quot;&gt;Youtube channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://iot-analytics.com/5-iot-sensor-technologies/&quot;&gt;&lt;strong&gt;5 IoT Sensor Technologies to Watch&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
According to this detailed article from iot-analytics.com, on average, four new sensors are connected with every new IoT device that comes online. With approximately 14 billion current IoT connections, this means more than 50 billion connected sensors have been deployed. IoT sensor technology plays a crucial role in the IoT tech stack because these sensors collect data from the physical world and convert it into digital signals. We think &lt;a href=&quot;https://iot-analytics.com/5-iot-sensor-technologies/&quot;&gt;their article&lt;/a&gt; is worth a read.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-string&quot;&gt;&lt;strong&gt;Custom Node Spotlight - node-red-contrib-string&lt;/strong&gt;&lt;/a&gt;
String manipulation is the bread and butter of so many programming tasks. Node-RED has a lot of tools to help you edit your strings including support for &lt;a href=&quot;https://jsonata.org/&quot;&gt;JSONata&lt;/a&gt; and using the trusty function node. For those of us who prefer to keep things &#39;no-code&#39; &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-string&quot;&gt;node-red-contrib-string&lt;/a&gt; allows you to stack string manipulations together quickly and easily. It has a huge library of ready to use functions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/team/&quot;&gt;&lt;strong&gt;FlowFuse Team News&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We’d like to welcome two new members to the FlowFuse team. &lt;a href=&quot;https://twitter.com/ianskerrett&quot;&gt;Ian Skerrett&lt;/a&gt; has joined as our Head of Marketing and &lt;a href=&quot;https://www.linkedin.com/in/tracyanthonyfernandez/&quot;&gt;Tracy Anthony&lt;/a&gt; has joined as our HR Manager. FlowFuse continues to grow and we are becoming a truly global team.&lt;/p&gt;
&lt;p&gt;Would you like to work for FlowFuse? We are currently recruiting &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004&quot;&gt;NodeJS Developers&lt;/a&gt; to join our team. You can view any of the roles we currently have open and apply on our &lt;a href=&quot;https://boards.greenhouse.io/flowfuse&quot;&gt;Jobs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create?code=FF12&quot;&gt;&lt;strong&gt;Try FlowFuse for Free&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As a thank you for reading our newsletters we’d like to offer you a free, small project for one month on our managed FlowFuse platform when you create a new team. To get this discount please follow &lt;a href=&quot;https://app.flowfuse.com/account/create?code=FF12&quot;&gt;this link&lt;/a&gt; or use the code FF12 when on the payment page after creating a new team. As an open source project you can also use &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;FlowFuse&lt;/a&gt; for free, forever.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/</id>
        <title>FlowFuse 1.2 is now available with single sign on and persistent context storage</title>
        <summary>Our final release for 2022 with some great new features to try out</summary>
        <updated>2022-12-22T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Control access to FlowFuse using single sign-on and retain context values when restarting projects.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 1.2 is now available! The latest release of the FlowFuse application contains new features, improvements, better documentation, and bug fixes.&lt;/p&gt;
&lt;p&gt;We&#39;ve put a great deal of work in this release to make it easier to run your own self-managed instance of FlowFuse. That includes significant improvements for FlowFuse in &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/226&quot;&gt;Single Sign-On&lt;/a&gt; Single sign-on (SSO) is a method of authentication that allows a user to access multiple applications or systems with a single set of login credentials, improving security, productivity, and user experience, and reducing IT overhead. We&#39;ve implemented SSO using the Security Assertion Markup Language &lt;a href=&quot;https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language&quot;&gt;(SAML)&lt;/a&gt; framework. This allows users of FlowFuse Cloud, Premium and the open source edition to easily access their FlowFuse projects.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/212&quot;&gt;Persistent Context&lt;/a&gt; Node-RED provides a way to store information that can be shared between different nodes and flow executions without using the messages that pass through a flow. This is called ‘context’. You can now select if context should be stored in memory or in persistent storage. Persistent storage allows the stored values to be recalled after a restart of your project. You can see a demonstration of this feature on our &lt;a href=&quot;https://youtu.be/ma2vYrXmssc&quot;&gt;Youtube channel&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In FlowFuse 1.1 we added logging of user actions. In 1.2 we’ve &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/517&quot;&gt;improved the audit log interface&lt;/a&gt; to help you read the recorded user actions.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;An image of the new audit log interface of FlowFuse&quot; alt=&quot;&amp;quot;An image of the new audit log interface of FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/audit-log.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configuring DNS for FlowFuse has historically been challenging as for most FlowFuse installs you&#39;ll need two entries. One for the FlowFuse application, and one for the Node-RED projects. There&#39;s been updates to the documentation to make it much easier to set this up, and much faster. Please checkout the new &lt;a href=&quot;https://flowfuse.com/docs/install/dns-setup/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We&#39;ve updated our documentation to always link to the latest build (older builds are still available).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Previously customers were asked to build their own containers for the main FlowFuse applications, as well as the Node-RED ones. For the Node-RED containers this allows customers to pre-install packages in the container they intent to use. For FlowFuse Cloud these containers are build by FlowFuse. These containers are now published to the &lt;a href=&quot;https://hub.docker.com/u/flowforge&quot;&gt;Docker Hub&lt;/a&gt;. This makes it much easier to get up and running with your first containers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We are now pushing our Docker builds to Docker Hub, this saves users from having to build the Docker images when installing or updating. These containers are used by default by &lt;code&gt;docker-compose&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setting up MQTT for inter-project communication and communication with devices has been simplified. Please read the improved the documentation around configuration of &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1397&quot;&gt;MQTT&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Unable to edit &#39;Prevent Install of External nodes&#39; template option &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1376&quot;&gt;#1376&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Self-managed FlowFuse needs an external email server to deliver email to users. FlowFuse should be able deal with the email server being offline and gracefully recover once it is back online. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1159&quot;&gt;#1159&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Duplicate Activity Log for Project whose state is in flight &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1461&quot;&gt;#1461&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/flecoufle&quot;&gt;flecoufle&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/59&quot;&gt;#59&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sumanpaikdev&quot;&gt;sumanpaikdev&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/53&quot;&gt;#53&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sdirosa&quot;&gt;sdirosa&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/1326&quot;&gt;#1326&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building.
If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In 1.2 we&#39;ve continued to improve the experience of running your own self managed FlowFuse installation. We&#39;re confident you can have self managed FlowFuse running locally in under 30 minutes.
You can install our &lt;a href=&quot;https://flowfuse.com/docs/contribute/local/&quot;&gt;local build&lt;/a&gt;, through &lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt;, or &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create?code=FF12&quot;&gt;Sign up for FlowFuse Cloud&lt;/a&gt;
with the coupon &lt;strong&gt;FF12&lt;/strong&gt; to get your first project free for a month.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.2. To use
persistent context you&#39;ll need to upgrade your projects stack.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-2-0-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ve also added a live chat widget to our website, you can access it using the icon on the bottom right corner of our website. We&#39;d love to hear from you.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/what-flowforge-adds-to-node-red/</id>
        <title>Why you need FlowFuse when you already have Node-RED?</title>
        <summary>FlowFuse makes developer collaboration, flow deployment, and scaling of infrastructure easy when working with Node-RED</summary>
        <updated>2022-12-15T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/what-flowforge-adds-to-node-red/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Many organizations face challenges in IT/OT convergence. There are many protocols, disparate devices, and everything is a brownfield project. Furthermore, skilled engineers are hard to find. Many organizations find themselves maintaining systems and integrations, and have little time left to improve continuously.&lt;/p&gt;
&lt;p&gt;This is why Node-RED is adopted so widely, it makes a world of difference through two of its properties: Low-Code Development and the ability to integrate with a wide range of hardware and software systems. Node-RED makes it easy to program data collection, then use that data for decision making, and provide feedback to both your digital platform and the physical reality of your business. Furthermore, Node-RED is unrivalled in making data accessible. The data previously locked in a walled garden of your hardware providers is now accessible and obtainable. With that, more data is available and better decisions are made, faster.&lt;/p&gt;
&lt;p&gt;FlowFuse makes developer collaboration, flow deployment, and scaling of infrastructure easy when working with Node-RED. It offers an intuitive user interface for creating, deploying, monitoring, and managing multiple Node-RED projects. FlowFuse also provides one-click deployment to thousands of devices, making it easy to manage large-scale environments.&lt;/p&gt;
&lt;p&gt;These features make FlowFuse a valuable tool for organizations using Node-RED to build applications and automate processes. Enabling for further adoption of Node-RED to integrate more systems, for even better decisions.&lt;/p&gt;
&lt;p&gt;This not only reduces operational costs but it also allows an organization to be far more agile with their Node-RED projects than was possible without FlowFuse.&lt;/p&gt;
&lt;p&gt;We would be happy to talk to you more about how FlowFuse can help you get the most value from Node-RED. Please &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;contact us&lt;/a&gt; to learn more.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/flowforge-joins-openjs-foundation/</id>
        <title>FlowFuse Inc. becomes a member of the OpenJS Foundation</title>
        <summary>Supporting the foundation that has given Node-RED a great home</summary>
        <updated>2022-12-13T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/flowforge-joins-openjs-foundation/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;We&#39;re pleased to share the news we&#39;ve joined the OpenJS Foundation to bolster our
support for the Node-RED community.&lt;/p&gt;
&lt;p&gt;One of our &lt;a href=&quot;https://flowfuse.com/handbook/company/principles/#open-source-stewardship&quot;&gt;founding principles&lt;/a&gt; is
the importance of Open Source being at the core of what we do.&lt;/p&gt;
&lt;p&gt;Node-RED has been part of the &lt;a href=&quot;https://openjsf.org/&quot;&gt;OpenJS Foundation&lt;/a&gt; since it was formed in 2019.
The Foundation provides the project a vendor-neutral home and enables its open governance model that
allows anyone to get involved.&lt;/p&gt;
&lt;p&gt;It also provides some vitally important resources to the community, such as the hosting for the
&lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;community forum&lt;/a&gt;, which regularly gets over 1.5 Million page views a
month.&lt;/p&gt;
&lt;p&gt;With my Node-RED Project Lead hat on, I regularly see the impact the foundation has had on the growth
of the Node-RED community. These are things that may not always be obvious to our end users, but
we wouldn&#39;t be where we are today with them.&lt;/p&gt;
&lt;p&gt;The success of what we&#39;re building with FlowFuse relies on a strong and healthy Node-RED community.
Becoming members of the Foundation allows us to provide more yet more support to Node-RED and the wider
JavaScript communities represented by the foundation.&lt;/p&gt;
&lt;p&gt;For more information about this news, check out the &lt;a href=&quot;https://openjsf.org/announcement/2022/12/13/welcoming-flowforge-to-the-openjs-foundation/&quot;&gt;OpenJS Foundation blog post&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/</id>
        <title>FlowFuse 1.1.2 released</title>
        <summary>Release includes a fix for installing additional nodes into Node-RED.</summary>
        <updated>2022-12-09T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;We&#39;ve published a maintenance fix with an important fix for the Palette Manager in Node-RED.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1367&quot;&gt;bug&lt;/a&gt; was reported this week
where a user was unable to install additional nodes into their Node-RED project
using the editor&#39;s palette manager.&lt;/p&gt;
&lt;p&gt;We tracked it down to an issue that was introduced in the 1.1 release, where the
project template lets you list nodes that should be blocked from being installed.
It was interpreting an empty list to mean &lt;em&gt;disallow everything&lt;/em&gt;! Not quite the
intended behaviour.&lt;/p&gt;
&lt;p&gt;Whilst tracking this down, we also spotted a bug (&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1379&quot;&gt;#1379&lt;/a&gt;)
around editing this same setting that made it tricky to work around without this
release being published.&lt;/p&gt;
&lt;p&gt;These issues have now been fixed and FlowFuse 1.1.2 published.&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In additional to the above issues, this release includes some further fixes around
the docker and helm components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix fileStore hostname by @flecoufle in &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/59&quot;&gt;#59&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fix healthcheck &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/62&quot;&gt;#62&lt;/a&gt; &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/63&quot;&gt;#63&lt;/a&gt; &lt;a href=&quot;https://github.com/FlowFuse/helm/pull/74&quot;&gt;#74&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like to thank the following people for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/flecoufle&quot;&gt;flecoufle&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/docker-compose/pull/59&quot;&gt;#59&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building.
If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This release has already been rolled out to &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-1-1-2-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform, please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/</id>
        <title>Configure FlowFuse in Docker to secure all traffic</title>
        <summary>Use Let&#39;s Encrypt and Acme Companion to quickly set up FlowFuse to encrypt all traffic</summary>
        <updated>2022-12-09T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Following on from our &lt;a href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/&quot;&gt;previous article&lt;/a&gt; in which we covered how to run FlowFuse in Docker on Google’s Cloud Platform, today we are going to look at how to secure HTTP traffic to your FlowFuse server.&lt;/p&gt;
&lt;h3 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When we wrote the first part of this series FlowFuse didn&#39;t have an easy path to secure HTTP traffic. Happily, two versions of FlowFuse later and at least partially inspired by these blogs, we have added the configuration you need in Docker to use HTTPS with minimal work.&lt;/p&gt;
&lt;p&gt;That addition makes our job of explaining this setup a lot easier, credit to our developers for seeing the value of having an easy implementation of HTTPS in FlowFuse as part of our &lt;a href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/&quot;&gt;1.0 build&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To achieve secure HTTPS traffic we are employing a great service called &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let&#39;s Encrypt&lt;/a&gt;. In their own words, &amp;quot;Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit&amp;quot;. In practice Let&#39;s Encrypt will allow us to easily secure HTTPS traffic.&lt;/p&gt;
&lt;p&gt;We are also utilising a Docker image called &lt;a href=&quot;https://github.com/nginx-proxy/acme-companion&quot;&gt;acme-companion&lt;/a&gt; which makes the configuration of Let&#39;s Encrypt a breeze. To quote the project&#39;s own Github page &amp;quot;acme-companion is a lightweight companion container for nginx-proxy. It handles the automated creation, renewal and use of SSL certificates for proxied Docker containers through the ACME protocol&amp;quot;. It&#39;s a great project and credit to the team over there for making it a lot easier to secure the internet.&lt;/p&gt;
&lt;p&gt;Now we&#39;ve covered our goals and the tools we are going to use let&#39;s configure our existing GCP VM to secure all web traffic.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned above, you will need to be running FlowFuse version 1.0 or higher to follow this guide. If you are using an older version you can upgrade now using the &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;instructions here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;update-docker-compose&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/#update-docker-compose&quot;&gt;Update Docker Compose&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step is to edit our Docker compose file. We&#39;re using Nano again to edit files so we will run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /opt/flowforge/docker-compose-1.1.1/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the docker-compose.yml file, un-comment the following lines:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-37&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-37&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./certs:/etc/nginx/certs&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-37&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-38&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-38&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;443:443&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-38&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-39&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-39&quot; class=&quot;language-yaml&quot;&gt; &lt;span class=&quot;token key atrule&quot;&gt;acme&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nginxproxy/acme&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;companion&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./acme:/etc/acme.sh&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;volumes_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; nginx&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;rw&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DEFAULT_EMAIL=mail@example.com&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token key atrule&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nginx&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-39&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We should also redirect all traffic to use HTTPS, to do that un-comment the following in the nginx service section:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-43&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-43&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;HTTPS_METHOD=redirect&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-43&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;We now need to add the configuration for LetsEncrypt, edit the following lines to include a valid email address and the correct domain for where you are hosting your FlowFuse server:&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-47&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-47&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DEFAULT_EMAIL=mail@example.com&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-47&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-48&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-48&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LETSENCRYPT_HOST=mqtt.example.com&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-48&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-49&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-49&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LETSENCRYPT_HOST=forge.example.com&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-49&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Save and exit from that file, in Nano you can do that by pressing ‘control x’ then ‘y’ then the Return key.&lt;/p&gt;
&lt;h3 id=&quot;update-flowforge.yml&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/#update-flowforge.yml&quot;&gt;Update flowforge.yml&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, we need to edit the public_url for the MQTT broker:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /opt/flowforge/docker-compose-1.1.1/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then replace ws:// with wss://&lt;/p&gt;

&lt;div style=&quot;position: relative&quot; id=&quot;code-container-63&quot;&gt;
  &lt;pre class=&quot;language-yaml&quot;&gt;&lt;code id=&quot;code-63&quot; class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;public_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wss&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//mqtt.flowforge&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;demo.com&lt;/code&gt;&lt;/pre&gt;

  &lt;button class=&quot;code-copy mdi mdi-content-copy&quot; data-clipboard-target=&quot;#code-63&quot; style=&quot;position: absolute; top: 7.5px; right: 6px; padding-top: 3px; cursor: pointer; outline: none; opacity: 0.8;&quot; title=&quot;Copy&quot;&gt;
    &lt;span style=&quot;display:inline-block;background:url() no-repeat center center / contain;background: initial&quot; class=&quot;&quot;&gt;&lt;/span&gt;
  &lt;/button&gt;
&lt;/div&gt;
&lt;p&gt;Save and exit from that file, in Nano you can do that by pressing ‘control x’ then ‘y’ then the Return key.&lt;/p&gt;
&lt;h3 id=&quot;restart-your-docker-containers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/flowforge-gcp-https-set-up/#restart-your-docker-containers&quot;&gt;Restart your Docker containers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OK, we should be ready to restart the Docker containers, run the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo docker compose -p flowforge up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you reload your FlowFuse root directory in a web browser you should now see that your traffic is encrypted using LetsEncypt.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;A screenshot from Safari web browser showing that the traffic to FlowFuse is encrypted&quot; alt=&quot;A screenshot from Safari web browser showing that the traffic to FlowFuse is encrypted&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/https-working.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Nice! That’s it, you can now access your FlowFuse installation securely.&lt;/p&gt;
&lt;p&gt;In the next and final part of this series of articles, we are going to look at how we can actually use FlowFuse including how to build flows and deploy and update them on Devices linked to a project.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/create-http-trigger-with-authentication/</id>
        <title>Create HTTP triggers with authentication</title>
        <summary>From any browser or command line you now have the ability to securely trigger your flows</summary>
        <updated>2022-12-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/create-http-trigger-with-authentication/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Having an HTTP endpoint trigger your flows is very useful. From any browser or command line you now have the ability to trigger your flows.
Doing so safely with authentication is slightly harder, but not a lot. FlowFuse makes it rather easy to accomplish.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-http-flow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/create-http-trigger-with-authentication/#creating-the-http-flow&quot;&gt;Creating the HTTP flow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you start a project on FlowFuse, remember the project name. For this how-to we’ll use &lt;code&gt;example&lt;/code&gt;. Open the editor and drag in the HTTP In node as well as the HTTP response node. Connect them, and add a debug node, which is connected to the “HTTP in” node.&lt;/p&gt;
&lt;p&gt;First off; let’s set the HTTP in node properties:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Shows the UI to edit the node&#39;s properties&quot; alt=&quot;Shows the UI to edit the node&#39;s properties&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/edit-http-node.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can import this flow into your own project if you’d like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[{&amp;quot;id&amp;quot;:&amp;quot;4faa84d37a52bb28&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;group&amp;quot;,&amp;quot;z&amp;quot;:&amp;quot;3c6e2dc732ada815&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Allow HTTP Post request to trigger a flow&amp;quot;,&amp;quot;style&amp;quot;:{&amp;quot;label&amp;quot;:!0},&amp;quot;nodes&amp;quot;:[&amp;quot;1fa26e0ed3ddec1a&amp;quot;,&amp;quot;45a180052e1a2f43&amp;quot;,&amp;quot;09347881f4fa4057&amp;quot;],&amp;quot;x&amp;quot;:34,&amp;quot;y&amp;quot;:79,&amp;quot;w&amp;quot;:472,&amp;quot;h&amp;quot;:122},{&amp;quot;id&amp;quot;:&amp;quot;1fa26e0ed3ddec1a&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;http in&amp;quot;,&amp;quot;z&amp;quot;:&amp;quot;3c6e2dc732ada815&amp;quot;,&amp;quot;g&amp;quot;:&amp;quot;4faa84d37a52bb28&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;HTTP Trigger&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;/http-trigger&amp;quot;,&amp;quot;method&amp;quot;:&amp;quot;post&amp;quot;,&amp;quot;upload&amp;quot;:!1,&amp;quot;swaggerDoc&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;x&amp;quot;:130,&amp;quot;y&amp;quot;:120,&amp;quot;wires&amp;quot;:[[&amp;quot;45a180052e1a2f43&amp;quot;,&amp;quot;09347881f4fa4057&amp;quot;]]},{&amp;quot;id&amp;quot;:&amp;quot;45a180052e1a2f43&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;http response&amp;quot;,&amp;quot;z&amp;quot;:&amp;quot;3c6e2dc732ada815&amp;quot;,&amp;quot;g&amp;quot;:&amp;quot;4faa84d37a52bb28&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Empty HTTP response&amp;quot;,&amp;quot;statusCode&amp;quot;:&amp;quot;200&amp;quot;,&amp;quot;headers&amp;quot;:{},&amp;quot;x&amp;quot;:360,&amp;quot;y&amp;quot;:120,&amp;quot;wires&amp;quot;:[]},{&amp;quot;id&amp;quot;:&amp;quot;09347881f4fa4057&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;debug&amp;quot;,&amp;quot;z&amp;quot;:&amp;quot;3c6e2dc732ada815&amp;quot;,&amp;quot;g&amp;quot;:&amp;quot;4faa84d37a52bb28&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Print HTTP Request&amp;quot;,&amp;quot;active&amp;quot;:!0,&amp;quot;tosidebar&amp;quot;:!0,&amp;quot;console&amp;quot;:!1,&amp;quot;tostatus&amp;quot;:!1,&amp;quot;complete&amp;quot;:&amp;quot;payload&amp;quot;,&amp;quot;targetType&amp;quot;:&amp;quot;msg&amp;quot;,&amp;quot;statusVal&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;statusType&amp;quot;:&amp;quot;auto&amp;quot;,&amp;quot;x&amp;quot;:360,&amp;quot;y&amp;quot;:160,&amp;quot;wires&amp;quot;:[]}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I’ve opened a terminal and executed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST https://example.flowforge.com/http-trigger
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When there’s no output, that means it’s all good! There should be an empty message in the debug console in the Node-RED editor though&lt;/p&gt;
&lt;h3 id=&quot;securing-the-http-trigger-with-a-username-and-password&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/create-http-trigger-with-authentication/#securing-the-http-trigger-with-a-username-and-password&quot;&gt;Securing the HTTP trigger with a username and password&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The problem with our trigger is that anyone with internet access could trigger it. That’s not a great idea. So let’s secure this endpoint with HTTP Basic Authentication. There are various ways to include a secure endpoint in Node-RED, we’ve built authentication directly into FlowFuse to make it easier for all users. On the FlowFuse project, go to settings and then to ‘Editor’. Under the section HTTP Auth you can set a username and password. You should generate both by a random string generator, and store the credentials somewhere safe.  Restart the project to have the runtime pick up the changes, and the endpoint is secured!&lt;/p&gt;
&lt;p&gt;Let’s validate the endpoint that worked a minute ago doesn’t anymore:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST https://example.flowforge.cloud/http-trigger
=&amp;gt; Unauthorized
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s get it working again: (replace &lt;username&gt; and &lt;password&gt; with the details from the sticky note)&lt;/password&gt;&lt;/username&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST https://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@example.flowforge.cloud/http-trigger
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it! You now have a flow that’s protected by a username and password combination!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/</id>
        <title>Format your Node-RED flows for better team collaboration</title>
        <summary>From formatting your flows for readability to providing clear comments on nodes and groups, a little bit of effort upfront can save your team a lot of headaches down the road</summary>
        <updated>2022-12-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;When it comes to working on Node-RED flows as part of a team, there are a few best practices that can make things go more smoothly.
From formatting your flows for readability to providing clear comments on nodes and groups, a little bit of effort upfront can save your team a lot of headaches down the road. In this post, we&#39;ll cover some of the main things to keep in mind when working on Node-RED flows as part of a team.&lt;/p&gt;
&lt;h3 id=&quot;give-your-groups-descriptive-names&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#give-your-groups-descriptive-names&quot;&gt;Give your groups descriptive names&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s start with &lt;a href=&quot;https://nodered.org/docs/user-guide/editor/workspace/groups&quot;&gt;grouping your flows&lt;/a&gt; and giving each group a clear explanation of what it does. Compare the first to the second example below and consider how much more quickly you can understand what the flow is doing.&lt;/p&gt;
&lt;h4 id=&quot;this-is-not-helpful%2C-&#39;time&#39;-doesn&#39;t-tell-you-enough-to-understand-the-flow&#39;s-purpose.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-not-helpful%2C-&#39;time&#39;-doesn&#39;t-tell-you-enough-to-understand-the-flow&#39;s-purpose.&quot;&gt;This is not helpful, &#39;Time&#39; doesn&#39;t tell you enough to understand the flow&#39;s purpose.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the example of flow having the bad group name&quot; alt=&quot;&amp;quot;Screenshot showing the example of flow having the bad group name&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/name-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;this-is-much-better%2C-we-know-what-the-flow-is-doing-without-inspecting-the-nodes.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-much-better%2C-we-know-what-the-flow-is-doing-without-inspecting-the-nodes.&quot;&gt;This is much better, we know what the flow is doing without inspecting the nodes.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the example of flow having the good group name&quot; alt=&quot;&amp;quot;Screenshot showing the example of flow having the good group name&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/name-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;explain-what-your-switches-do&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#explain-what-your-switches-do&quot;&gt;Explain what your switches do&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Try to make it obvious what each switch does without having to open the node editor. Ask a question in the switch&#39;s name and make a positive answer the top connection out.&lt;/p&gt;
&lt;h4 id=&quot;this-is-not-easy-to-understand%2C-what-does-the-switch-do%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-not-easy-to-understand%2C-what-does-the-switch-do%3F&quot;&gt;This is not easy to understand, what does the switch do?&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the example of flow having the switch with bad name&quot; alt=&quot;&amp;quot;Screenshot showing the example of flow having the switch with bad name&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/switch-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;this-is-a-lot-better%2C-we-can-see-that-the-top-debug-should-be-triggered.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-a-lot-better%2C-we-can-see-that-the-top-debug-should-be-triggered.&quot;&gt;This is a lot better, we can see that the top debug should be triggered.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the example of flow having the switch with good name&quot; alt=&quot;&amp;quot;Screenshot showing the example of flow having the switch with good name&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/switch-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;where-possible-your-flows-should-work-down-the-canvas&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#where-possible-your-flows-should-work-down-the-canvas&quot;&gt;Where possible your flows should work down the canvas&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It makes it so much easier to understand what happens and in which order if your flows start at the top of the canvas and work down to the bottom.&lt;/p&gt;
&lt;h4 id=&quot;this-is-almost-unreadable%2C-it&#39;s-very-hard-to-work-out-the-order-of-the-groups.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-almost-unreadable%2C-it&#39;s-very-hard-to-work-out-the-order-of-the-groups.&quot;&gt;This is almost unreadable, it&#39;s very hard to work out the order of the groups.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow that doesn&#39;t work down the canvas&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow that doesn&#39;t work down the canvas&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowdown-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;where-as-this-is-so-much-easier-to-understand.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#where-as-this-is-so-much-easier-to-understand.&quot;&gt;Where as this is so much easier to understand.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow that works down the canvas&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow that works down the canvas&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/flowdown-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;use-link-nodes-rather-than-wires-to-join-groups&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#use-link-nodes-rather-than-wires-to-join-groups&quot;&gt;Use link nodes rather than wires to join groups&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Groups should not be joined using wires, it just looks untidy and quickly reduces readability of your flows.&lt;/p&gt;
&lt;h4 id=&quot;the-wire-is-blocking-the-title%2C-it-only-gets-worse-as-you-add-more-wires.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#the-wire-is-blocking-the-title%2C-it-only-gets-worse-as-you-add-more-wires.&quot;&gt;The wire is blocking the title, it only gets worse as you add more wires.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow with wires blocking group titles&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow with wires blocking group titles&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/link-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;you-can-see-the-group-titles-easily-now.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#you-can-see-the-group-titles-easily-now.&quot;&gt;You can see the group titles easily now.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow with link nodes improving readability&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow with link nodes improving readability&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/link-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;keep-your-groups-compact&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#keep-your-groups-compact&quot;&gt;Keep your groups compact&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Keeping your groups compact will save time when reading the flow. This is especially helpful if when viewed on a smaller screen.&lt;/p&gt;
&lt;h4 id=&quot;consider-how-hard-a-flow-made-of-groups-spaced-out-like-this-would-be-to-read-on-a-smaller-laptop-screen.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#consider-how-hard-a-flow-made-of-groups-spaced-out-like-this-would-be-to-read-on-a-smaller-laptop-screen.&quot;&gt;Consider how hard a flow made of groups spaced out like this would be to read on a smaller laptop screen.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow with widely spaced groups&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow with widely spaced groups&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;this-now-takes-up-less-space-and-is-arguably-easier-to-read-on-any-screen-size.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-now-takes-up-less-space-and-is-arguably-easier-to-read-on-any-screen-size.&quot;&gt;This now takes up less space and is arguably easier to read on any screen size.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of flow with compact groups&quot; alt=&quot;&amp;quot;Screenshot showing an example of flow with compact groups&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/compact-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;don%E2%80%99t-cross-beams-wires&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#don%E2%80%99t-cross-beams-wires&quot;&gt;Don’t cross &lt;s&gt;beams&lt;/s&gt; wires&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Crossed wires are not only hard to read, they can lead to misinterpretation of what a flow actually does. Where possible don’t cross your wires, where you can’t avoid it try to make sure it’s easy for the reader to understand where wires cross as rather than join.&lt;/p&gt;
&lt;h4 id=&quot;this-is-confusing%2C-which-change-node-does-the-top-switch-output-link-to%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-confusing%2C-which-change-node-does-the-top-switch-output-link-to%3F&quot;&gt;This is confusing, which change node does the top switch output link to?&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of the flow with nodes having crossed beams/wires&quot; alt=&quot;&amp;quot;Screenshot showing an example of the flow with nodes having crossed beams/wires&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/wires-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;this-is-better%2C-much-less-chance-of-confusing-the-change-nodes.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-better%2C-much-less-chance-of-confusing-the-change-nodes.&quot;&gt;This is better, much less chance of confusing the change nodes.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of the flow with nodes having correctly linked beams/wires&quot; alt=&quot;&amp;quot;Screenshot showing an example of the flow with nodes having correctly linked beams/wires&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/wires-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;don%E2%80%99t-use-link-nodes-in-groups-where-avoidable&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#don%E2%80%99t-use-link-nodes-in-groups-where-avoidable&quot;&gt;Don’t use link nodes in groups where avoidable&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Excessive link nodes within groups can make a flow much harder to understand, where possible use wires to join nodes within a group.&lt;/p&gt;
&lt;h4 id=&quot;this-is-hard-to-read-and-you-will-end-up-checking-the-link-nodes-again-and-again.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#this-is-hard-to-read-and-you-will-end-up-checking-the-link-nodes-again-and-again.&quot;&gt;This is hard to read and you will end up checking the link nodes again and again.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the example of flow having the uneccessary link nodes&quot; alt=&quot;&amp;quot;Screenshot showing the example of flow having the uneccessary link nodes&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/groupwires-bad.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h4 id=&quot;functionally-identical-to-the-example-above%2C-it-should-only-take-a-few-seconds-to-understand-this-flow-now.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#functionally-identical-to-the-example-above%2C-it-should-only-take-a-few-seconds-to-understand-this-flow-now.&quot;&gt;Functionally identical to the example above, it should only take a few seconds to understand this flow now.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing an example of the flow with the avoided link nodes&quot; alt=&quot;&amp;quot;Screenshot showing an example of the flow with the avoided link nodes&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/groupwires-good.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;boost-collaboration-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#boost-collaboration-with-flowfuse&quot;&gt;Boost Collaboration with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is a cloud-based platform that makes working together on Node-RED projects easier and more efficient. It’s trusted by industries like manufacturing and smart building management, as well as textiles, to improve their systems. For more information, refer to our &lt;a href=&quot;https://flowfuse.com/customer-stories/&quot;&gt;customer stories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With FlowFuse, you can quickly &lt;a href=&quot;https://flowfuse.com/docs/user/team/&quot;&gt;set up and manage teams&lt;/a&gt;, giving each member the right level of access. It keeps all your &lt;a href=&quot;https://www.youtube.com/watch?v=KOnQnR7yfT0&amp;amp;list=PLpcyqc7kNgp3nRacWBJ9JUVUJqtTjXdvh&amp;amp;index=2&quot;&gt;Node-RED instances organized in one place&lt;/a&gt;, so your team can collaborate seamlessly. Plus, it features &lt;a href=&quot;https://www.youtube.com/watch?v=m2Onip4Lf4w&quot;&gt;snapshots&lt;/a&gt;, which let you restore previous versions of your flows if something goes wrong. FlowFuse simplifies team collaboration, making it easier to manage and work on Node-RED projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt; now for a free trial and experience FlowFuse&#39;s powerful collaboration tools!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/12/node-red-flow-best-practice/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Working on Node-RED flows as part of a team doesn&#39;t have to be a headache. By following some simple best practices you can make collaboration smooth sailing for everyone involved. So next time you&#39;re starting work on a new Node-RED flow, remember these tips and make life easier for yourself and your teammates.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/12/community-news-11/</id>
        <title>Community News November 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-12-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/12/community-news-11/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for November 2022, a monthly roundup of what’s been happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you think we should share on our newsletters please &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;get it touch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-red/node-red/milestone/19&quot;&gt;&lt;strong&gt;Node-RED Nears 3.1 Release&lt;/strong&gt;&lt;/a&gt;
As we mentioned last month, the release of Node-RED 3.1 is expected very soon. 3.1 includes lots of great new features such as support for &lt;a href=&quot;https://github.com/node-red/node-red/pull/3938&quot;&gt;locking flows in the editor&lt;/a&gt; and &lt;a href=&quot;https://github.com/node-red/node-red/pull/3930&quot;&gt;improving the user experience around hiding flows&lt;/a&gt;. As an open source project the development of Node-RED is entirely dependent on individuals and companies giving their time to work towards each new release. If you&#39;d like to know how you can get involved you can read more on the &lt;a href=&quot;https://nodered.org/about/contribute/&quot;&gt;Node-RED web site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/&quot;&gt;&lt;strong&gt;FlowFuse 1.1 Released&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Version 1.1 of FlowFuse was released on 24th November. Our latest release included some great new features such as &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/998&quot;&gt;Persistent file storage&lt;/a&gt;, the ability to &lt;a href=&quot;https://flowfuse.com/docs/migration/node-red-tools/&quot;&gt;import Node-RED snapshots&lt;/a&gt; from outside of FlowFuse and a much improved interface to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1046&quot;&gt;deploy projects to your devices&lt;/a&gt;. We&#39;re now working towards our final release of 2022 which is due just before Christmas. You can see what we are planning to deliver in that release and beyond on &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;FlowFuse&#39;s project board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 1.1 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/&quot;&gt;blog post&lt;/a&gt;, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v1.1.0&quot;&gt;GitHub release page&lt;/a&gt;, and &lt;a href=&quot;https://www.youtube.com/watch?v=134iljE_urI&quot;&gt;Youtube channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/playfultechnology/node-redscape&quot;&gt;&lt;strong&gt;Node-Redscape - 100% Free, Open-Source Escape Room Control Software&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As we&#39;ll come to later in this newsletter, FlowFuse visited an Escape Room in Winchester as part of our team meet-up. Co-incidentally, a great Node-RED project came up a few days after our visit which we thought was worth sharing. In their own words &lt;a href=&quot;https://github.com/playfultechnology/node-redscape&quot;&gt;Node-Redscape&lt;/a&gt; &#39;provides a set of templates, flows, and examples that turn Node-RED into a complete Escape Room automation system&#39;. Very topical for us and also seems like a great project. You can learn more about the project on &lt;a href=&quot;https://www.youtube.com/watch?v=f9yYDxqK_2E&quot;&gt;Youtube&lt;/a&gt; as well as on &lt;a href=&quot;https://github.com/playfultechnology/node-redscape&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FlowFuse team meetup&lt;/strong&gt;
FlowFuse is a fully remote team, we currently have a strong skew towards western Europe but we are in the process of adding team members in each of the continents. On that point, any great Product Managers who live in Antarctica are encouraged to &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4717778004&quot;&gt;apply for a job with us&lt;/a&gt;! Remote work is great but it&#39;s also valuable to get everyone together in the real world from time to time. FlowFuse had such a meet up last month in Winchester, UK. We came from near and far and took the opportunity to have productive round-table discussions about some features we are working towards in 1.2 and beyond.  We also dropped into &lt;a href=&quot;https://cluecapers.co.uk/&quot;&gt;Clue Capers&lt;/a&gt;, a great Escape Room in the center of Winchester who provided the photo below to mark the occasion.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;The FlowFuse team pictured during our visit to Clue Capers&quot; alt=&quot;&amp;quot;The FlowFuse team pictured during our visit to Clue Capers&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/clue-capers.jpg&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/team/&quot;&gt;&lt;strong&gt;FlowFuse Team News&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We are currently recruiting a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4717778004&quot;&gt;Product Manager&lt;/a&gt;, and a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4700809004&quot;&gt;Senior Community Manager&lt;/a&gt;. You can view any of the roles we currently have open and apply on our &lt;a href=&quot;https://boards.greenhouse.io/flowfuse&quot;&gt;Jobs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE11&quot;&gt;&lt;strong&gt;Try FlowFuse for Free&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As a thank you for reading our newsletters we’d like to offer you a free, small project for one month on our managed FlowFuse platform when you create a new team. To get this discount please follow &lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE11&quot;&gt;this link&lt;/a&gt; or use the code RELEASE11 when on the payment page after creating a new team. As an open source project you can also use &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;FlowFuse&lt;/a&gt; for free, forever.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/</id>
        <title>Challenges scaling Node-RED with DIY tooling</title>
        <summary>Node-RED is very easy to get up and running for your first instance but what about your 100th?</summary>
        <updated>2022-11-30T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;In this post, I&#39;m going to share some of the challenges customers face when
scaling Node-RED with Do-It-Yourself tooling.
Specifically, we&#39;ll talk about
common threads in their journey building their own tooling around Node-RED, its
flows, and deploying them. Node-RED is a visual programming environment for
wiring together hardware devices, APIs and online services in a single
application. It&#39;s great because it&#39;s flexible enough to be used by both
beginners and experts alike; however, going from one instance of Node-RED to 100
isn&#39;t for the faint-hearted.&lt;/p&gt;
&lt;h3 id=&quot;zero-to-hero-in-a-few-days&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/#zero-to-hero-in-a-few-days&quot;&gt;Zero to hero in a few days&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you’re new to Node-RED and are just getting started, the first step is simple:
go to &lt;a href=&quot;https://nodered.org/&quot;&gt;nodered.org&lt;/a&gt;, download, install and run. There’s no
need to configure anything or set up credentials or security or alerts. You can
get started with Node-RED straight away by simply running it on your machine.
The guides and scripts provided on Node-RED or are more than enough to get
started. You&#39;ll dive right in and start developing your flows.&lt;/p&gt;
&lt;h3 id=&quot;onto-the-second-instance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/#onto-the-second-instance&quot;&gt;Onto the second instance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next instance is a simple copy of the first. You&#39;ll need to make sure that
you are installing the same version on both instances, and that any
configuration files (such as the &lt;code&gt;settings.js&lt;/code&gt;) are also in sync.&lt;/p&gt;
&lt;p&gt;The second instance improves the first equally. Docs are read again,
improvements are made, and copied over. Life&#39;s good! Although there&#39;s a slight
itch to start automating the setup, it&#39;s ignored. Just too many open questions
on how to achieve it: write scripts in bash? Or can we use Node-RED to manage
Node-RED? Automation can wait, there&#39;s new flows to implement!&lt;/p&gt;
&lt;h3 id=&quot;wake-up-call%3B-how-many-of-them-do-we-have%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/#wake-up-call%3B-how-many-of-them-do-we-have%3F&quot;&gt;Wake-up call; how many of them do we have?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There&#39;s nothing like a good ol&#39; wake-up call to get you back on track. One of
our team members asked a questions about a buggy flow you&#39;ve got no recollection
of. During the investigation there&#39;s issues left and right; it&#39;s running a much
older version, missing standard packages, the settings are out of date, and the
timezone not set to UTC? Adoption of Node-RED is going quite well, it&#39;s useful
and effective. Gets the job done without fuss. But now there&#39;s toil in
maintaining them; ensure the right tooling is build, properly documented, it
needs dashboards and overviews, lots of work to be done. Not quite business
related, but Node-RED is important for the company, the bosses sure would
approve spending 2 months building these tools!&lt;/p&gt;
&lt;p&gt;But then something happened—there was a higher priority project to be picked up.
Some tooling could be written for a couple of hours a month, but not two
dedicated months to get it in tip top shape. Better than nothing! Built a
dashboard in Node-RED to keep track of all devices, there&#39;s some scripts and a
few flows that aid in monitoring and maintenance. Scaling further is possible,
but confidence in the tooling isn&#39;t sky high.&lt;/p&gt;
&lt;h3 id=&quot;data-extraction-at-scale%3B-now-there&#39;s-over-100&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/#data-extraction-at-scale%3B-now-there&#39;s-over-100&quot;&gt;Data extraction at scale; now there&#39;s over 100&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; we&#39;ve got regular conversations with customers managing 100s of
devices. Scaling to that many devices and runtimes requires hours of development
each week alongside monitoring, maintenance, and auditing.&lt;/p&gt;
&lt;p&gt;As a side effect of investing more time into Node-RED and its ecosystem the
organization has developed a few standards. Standard custom nodes that are
pre-installed (👋 &lt;code&gt;moment.js&lt;/code&gt;), a style guide published for developing flows,
maybe even flow linting: https://github.com/node-red/nrlint&lt;/p&gt;
&lt;p&gt;The security model is fairly decent. One just hopes the
&lt;a href=&quot;https://nl.wikipedia.org/wiki/Chief_Information_Security_Officer&quot;&gt;CISO&lt;/a&gt; doesn&#39;t
inspects them, but it&#39;s a fair bet they won&#39;t; we&#39;re far away from the
headquarters, right?&lt;/p&gt;
&lt;p&gt;Many other edge cases itch in the back of our heads, but we can&#39;t focus on those right now.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/scaling-node-red-with-diy-tooling/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED is a great tool, it&#39;s got many built-in features that make it easy to
get started with no coding experience necessary. Running it at scale, in a
production environment can require a lot of sys-ops and dev-ops time and we
think &lt;a href=&quot;https://flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is a great solution to keep that admin and tech debt in check.&lt;/p&gt;
&lt;p&gt;If you&#39;re running into these challenges we believe we can help, you can adopt
our &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;free and open source edition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, to get a head start or enhance your current setup, explore our &lt;a href=&quot;https://flowfuse.com/ebooks/beginner-guide-to-a-professional-nodered/&quot;&gt;Beginner&#39;s Guide to Professional Node-RED&lt;/a&gt;. This comprehensive ebook offers a clear overview of Node-RED’s capabilities and practical tips for making the most of its features.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/11/respin-docker-compose-01/</id>
        <title>Re-spin of Docker-Compose install package</title>
        <summary>Adding ability to locally build file-server container</summary>
        <updated>2022-11-25T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/11/respin-docker-compose-01/"/>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;After &lt;a href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/&quot;&gt;yesterdays 1.1.0 FlowFuse release&lt;/a&gt; we noticed a few minor issues with the docker-compose install instructions.&lt;/p&gt;
&lt;p&gt;We had relied on the fact we are now publishing container images to Docker Hub to install the new &lt;code&gt;flowforge/file-server&lt;/code&gt; container. At this time we are only building images for amd64 and arm64. Further, it was only tagged them with the current release number.&lt;/p&gt;
&lt;p&gt;To remedy this we tagged v1.1.1 of the docker-compose project in which we have included the required &lt;code&gt;Dockerfile&lt;/code&gt; and resources to build the &lt;code&gt;flowforge/file-server&lt;/code&gt; locally, updated the &lt;code&gt;build-containers.sh&lt;/code&gt; script to build this container. We will also build the published containers for armv7 and include a latest tag going forward.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/11/flowforge-1-1-released/</id>
        <title>FlowFuse 1.1 released with persistent file storage</title>
        <summary>A new set of features to improve FlowFuse as the best solution for running Node-RED in production in a secure, scalable, and team-based environment.</summary>
        <updated>2022-11-24T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/11/flowforge-1-1-released/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Persist files on your FlowFuse Projects, publish locally developed flows to dozens of Devices in a few clicks, and use our new interface for managing Project Deployments.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 1.1 is now available! The latest release of the FlowFuse application contains new features, many improvements, and bug fixes. Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/998&quot;&gt;Persistent File Storage&lt;/a&gt; We&#39;ve had a great deal of feedback
from our customers that being able to persist files in a project is a vital feature
in Node-RED. In FlowFuse 1.1 flows can now create and persist files within
your Projects. We know those files are used in many creative ways and we&#39;re looking
forward to seeing how users improve their Projects using this new feature.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/docs/migration/node-red-tools/&quot;&gt;Import Snapshots from Outside FlowFuse&lt;/a&gt; Developers may wish to
work on Node-RED in a local environment but want an easy path to share that with their team. You can now link your Node-RED instances running outside of FlowFuse and push Snapshots directly into your FlowFuse Projects to leverage FlowFuse fully.  With this new feature we&#39;ve made it effortless to push a local build of a project to FlowFuse for deployment to your staging and production FlowFuse instances.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1046&quot;&gt;Project Deployments UX&lt;/a&gt;
We&#39;ve reworked the interface for managing your FlowFuse Deployments of Node-RED.
We are seeing FlowFuse users deploying their Projects to edge devices at scale.
This is another step towards making it easier for users to manage a large quantity
of devices in their Projects.&lt;/p&gt;
&lt;p&gt;When users change their username, email address, or password they&#39;ll now be
notified through email of changes to ensure they were made by the
user.&lt;/p&gt;
&lt;p&gt;In this release a lot of effort went into the install process, specifically the
local install method. First and foremost; a default Stack and Template will be
installed automatically. That will ensure users get up and running with
Node-RED more quickly. Administrators of each platform can still change Stacks
and Templates when needed. Secondly, the installer now auto generates the
configuration file for Mosquitto, the MQTT broker FlowFuse uses. This again should save
administrators time when installing FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The v1.0.1 release included a bug fix where &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1186&quot;&gt;snapshot rollbacks&lt;/a&gt;
didn&#39;t work, which has also been included in v1.1 onwards.&lt;/p&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When installing the stack during a FlowFuse installation the process would quit on Windows &lt;a href=&quot;https://github.com/FlowFuse/installer/issues/62&quot;&gt;#62&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After accepting an invite to join a team, users are no longer seeing a blank page &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1208&quot;&gt;#1208&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pagination on device deployments wasn&#39;t showing all devices &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1207&quot;&gt;#1207&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Markdown rendering when selecting the project type wasn&#39;t quite working, fixed now! &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1171&quot;&gt;#1171&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Continuous spinner in UI body when entering a new (short) password &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1280&quot;&gt;#1280&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Friendly stack name not shown in the Change Project Stack option list &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1169&quot;&gt;#1169&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The stacks view in the admin area didn&#39;t render properly &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1260&quot;&gt;#1260&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Like the deployments page, pagination for stacks was broken. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1164&quot;&gt;#1164&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Several UX and UI bugs got polished away!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mikermcneil&quot;&gt;mikermcneil&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/1301&quot;&gt;#1301&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building.
If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As said before, a lot of effort went into the local installer. We&#39;re confident
you can have your own FlowFuse running locally in about 30 minutes.
&lt;a href=&quot;https://flowfuse.com/docs/contribute/local/&quot;&gt;Get started right away!&lt;/a&gt;
(&lt;a href=&quot;https://flowfuse.com/docs/install/docker/&quot;&gt;Docker&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/docs/install/kubernetes/&quot;&gt;Kubernetes&lt;/a&gt;
are available too!)&lt;/p&gt;
&lt;p&gt;If you&#39;d rather use our hosted offering: &lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE11&quot;&gt;Sign up for FlowFuse Cloud&lt;/a&gt;
with the coupon &lt;strong&gt;RELEASE11&lt;/strong&gt; to get your first project free for a month.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 1.1. To use
persisted files you&#39;ll need to upgrade your projects stack. You&#39;ll be prompted
to do so on the project page.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading your FlowFuse instance&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/11/flowforge-1-1-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Please check FlowFuse&#39;s &lt;a href=&quot;https://flowfuse.com/docs/&quot;&gt;documentation&lt;/a&gt; as the answers to many questions are covered there.&lt;/p&gt;
&lt;p&gt;If you hit any problems with the platform please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Chat with us on the &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also raise a support ticket by emailing &lt;a href=&quot;mailto:support@flowfuse.com/&quot;&gt;support@flowfuse.com&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/11/community-news-10/</id>
        <title>Community News October 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-11-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/11/community-news-10/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter for October 2022, a monthly roundup of what’s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/&quot;&gt;&lt;strong&gt;FlowFuse 1.0 Released&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Version 1.0 was released on 27th October. Our latest release represents our vision of the base set of features needed for you to get great value from using FlowFuse in a production environment. That&#39;s not to say we are done, we will continue to add features, improve our interfaces and fix bugs with the same enthusiasm as we&#39;ve worked towards 1.0. We&#39;d like to hear your feedback on what we will be including in &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;1.1 and beyond&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 1.0 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/&quot;&gt;blog post&lt;/a&gt;, on our &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v1.0.0&quot;&gt;GitHub release page&lt;/a&gt; and on our &lt;a href=&quot;https://www.youtube.com/watch?v=5TLT7CQR7iI&quot;&gt;Youtube channel&lt;/a&gt;. We’d also love for more of you to get involved in the development of FlowFuse, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/blob/main/CONTRIBUTING.md&quot;&gt;contributions to the code&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;bug reports&lt;/a&gt; are really appreciated.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-red/node-red/milestone/19&quot;&gt;&lt;strong&gt;Node-RED Nears 3.1 Release&lt;/strong&gt;&lt;/a&gt;
The next release of Node-RED has some great new features including support for &lt;a href=&quot;https://github.com/node-red/node-red/pull/3938&quot;&gt;locking flows in the editor&lt;/a&gt; and &lt;a href=&quot;https://github.com/node-red/node-red/pull/3930&quot;&gt;improving the user experience around hiding flows&lt;/a&gt;. We&#39;d expect the first 3.1 beta to be available in November with a full release following shortly afterwards.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/10/seed-round-bring-node-red-to-enterprise/&quot;&gt;&lt;strong&gt;FlowFuse raises $7.25M to bring Node-RED to the Enterprise&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Earlier this week, we announced a $7.25M seed round led by &lt;a href=&quot;https://www.cotacapital.com/knowledgecapital/flowforge-closes-the-gap-between-it-and-ot&quot;&gt;Cota Capital&lt;/a&gt;, joined by Westwave Capital, Uncorrelated Ventures, and Open Core Ventures. This brings a huge amount of extensive knowledge and experience in IoT, open source, enterprise-ready software solutions. You can read more about what this investment means for FlowFuse in this &lt;a href=&quot;https://techcrunch.com/2022/11/03/flowforge-nabs-7-2m-to-help-companies-integrate-iot-using-node-red&quot;&gt;TechCrunch article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stevesnoderedguide.com/node-red-dashboard&quot;&gt;&lt;strong&gt;Node-RED Dashboard - Beginners Guide&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
It&#39;s great to see members of the Node-RED community taking their personal time to help us all build better projects. This write up takes you through the basics of creating your first Dashboard through to more advanced techniques to help your interfaces look professional and provide great user experiences.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/team/&quot;&gt;&lt;strong&gt;FlowFuse Team News&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We are currently recruiting &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004&quot;&gt;NodeJS Developers&lt;/a&gt;, a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4717778004&quot;&gt;Product Manager&lt;/a&gt;, a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4687876004&quot;&gt;Recruiter / PeopleOps Manager&lt;/a&gt; and a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4700809004&quot;&gt;Senior Community Manager&lt;/a&gt;. You can view any of the roles we currently have open and apply on our &lt;a href=&quot;https://boards.greenhouse.io/flowfuse&quot;&gt;Jobs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;d also like to welcome &lt;a href=&quot;https://github.com/Pezmc&quot;&gt;Pez Cuckow&lt;/a&gt; who joined FlowFuse as a Senior Software Engineer in October.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE1&quot;&gt;&lt;strong&gt;Try FlowFuse for Free&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As a thank you for reading our newsletters we’d like to offer you a free, small project for one month on our managed FlowFuse platform when you create a new team. To get this discount please follow &lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE010&quot;&gt;this link&lt;/a&gt; or use the code RELEASE1 when on the payment page after creating a new team. As an open source project you can also use &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;FlowFuse&lt;/a&gt; for free, forever.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/10/seed-round-bring-node-red-to-enterprise/</id>
        <title>FlowFuse raises $7.25M Seed Round to bring Node-RED to the Enterprise</title>
        <summary>Allowing all developers to integrate IT and OT through low-code</summary>
        <updated>2022-11-03T17:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/10/seed-round-bring-node-red-to-enterprise/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;Since the &lt;a href=&quot;https://flowfuse.com/blog/2021/04/first-deploy/&quot;&gt;launch of FlowFuse&lt;/a&gt; in April 2021 our goal has been to
build a low-code, enterprise-ready development platform based on Node-RED. We
wanted to make it easier for enterprises to adopt, integrate, and scale Node-RED
into their existing environments. We published our &lt;a href=&quot;https://flowfuse.com/blog/2022/01/flowforge-01-released/&quot;&gt;first version&lt;/a&gt;
at the start of this year and have continued the journey to the
&lt;a href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/&quot;&gt;launch of FlowFuse v1.0&lt;/a&gt; just last week. Each of these releases
has moved us towards our goal of creating a platform for integrating the
IT and OT for all organizations, built around an open core.&lt;/p&gt;
&lt;h3 id=&quot;flowfuse-is-node-red-for-the-enterprise&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/seed-round-bring-node-red-to-enterprise/#flowfuse-is-node-red-for-the-enterprise&quot;&gt;FlowFuse is Node-RED for the enterprise&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Node-RED is an incredible tool that has allowed many organizations to quickly
and easily integrate both their IT and OT. The sheer range and variety of
solutions created with Node-RED today go far beyond what we imagined. But we’ve
also seen the challenges faced by companies wanting to take their Node-RED
solutions into production and beyond.&lt;/p&gt;
&lt;p&gt;This is where FlowFuse comes in. It addresses those challenges by adding
security, collaboration and deployment capabilities.&lt;/p&gt;
&lt;h3 id=&quot;our-%247.25m-seed-round&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/seed-round-bring-node-red-to-enterprise/#our-%247.25m-seed-round&quot;&gt;Our $7.25M Seed Round&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today, we’re super excited to announce a $7.25M seed round led by Cota Capital,
joined by Westwave Capital, Uncorrelated Ventures, and Open Core Ventures. This
brings a huge amount of extensive knowledge and experience in IoT, open source,
enterprise-ready software solutions.&lt;/p&gt;
&lt;p&gt;This investment will enable us to continue growing the team and platform to
realize our vision of FlowFuse being the best way to achieve enterprise-ready
Node-RED. It will enable us to invest back into the core Node-RED project to
further its development. One of our core company principles is around Open
Source Stewardship - the success of FlowFuse relies on a strong and successful
Node-RED community.&lt;/p&gt;
&lt;p&gt;We’ll be bringing more collaboration features to the FlowFuse platform to
enable true collaborative, team-based working. We’ll expand our
&lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#device&quot;&gt;Devices offering&lt;/a&gt; to make it
far easier to run Node-RED wherever it suits your use-case, from data center to
remote edge locations.&lt;/p&gt;
&lt;p&gt;Above all, we’ll be building a company that is open, sustainable, and fun to
work at. We already have some job openings available - check out our
&lt;a href=&quot;https://boards.greenhouse.io/flowfuse&quot;&gt;jobs board&lt;/a&gt; if you’re interested in joining our
team.&lt;/p&gt;
&lt;p&gt;If you’re interested in learning more about what we’re doing, or have any
questions, please do &lt;a href=&quot;https://flowfuse.com/contact-us/&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/10/flowforge-1-released/</id>
        <title>FlowFuse 1.0 released</title>
        <summary>FlowFuse at 1.0, a huge milestone for us.</summary>
        <updated>2022-10-27T18:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/10/flowforge-1-released/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Predefined environment variables for your Instances and Devices, manage your Project&#39;s modules and import your existing flows (and credentials) into your FlowFuse &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#instance&quot;&gt;Projects&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.  --&gt;
&lt;p&gt;We&#39;re pleased to announce version 1.0 FlowFuse is now available. Keep reading for a promotion code to get your first month free on FlowFuse. Version 1.0 represents our vision of the base set of features needed for you to get great value from using FlowFuse in a production environment. That&#39;s not to say we are done, we will continue to add features, improve our interfaces and fix bugs with the same enthusiasm as we&#39;ve worked towards 1.0. We&#39;d like to hear your feedback on what we will be including in &lt;a href=&quot;https://github.com/orgs/FlowFuse/projects/5&quot;&gt;1.1 and beyond&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/841&quot;&gt;Standard Environment Variables set for both Projects and Devices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Projects now get a set of predefined environment variables that can be used by their flows. These give your flows access to the projects unique id and name. When the flows are deployed to &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#device&quot;&gt;devices&lt;/a&gt;, they also get the device&#39;s id and name. That makes is easier to deploy flows across multiple devices and have each able to identify itself.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/405&quot;&gt;Add additional node modules to your projects&lt;/a&gt;
This feature allows you to pre-define additional Node-RED nodes and node modules you may want to be installed in your FlowFuse project, making it easier to manage.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/835&quot;&gt;Import existing projects into FlowFuse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can now import your existing flow and credentials files straight into your FlowFuse project - making it really easy to move your existing projects into the platform.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made a number of improvements to the overall experience of running FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Editable Stack labels &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/915&quot;&gt;#915&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check for suitable version of Node on Devices &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/37&quot;&gt;#37&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Realtime Project status details in Project overview  &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/990&quot;&gt;#990&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve Template creation &amp;amp; Edit Project Settings UX &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1041&quot;&gt;#1041&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1143&quot;&gt;Pressing return in search box reloads page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1126&quot;&gt;Vue Router Warn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/forge-ui-components/issues/58&quot;&gt;Kebab menu in Settings breaks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1096&quot;&gt;flowforge-nr-launcher missing try/catch on http request&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1145&quot;&gt;Invite with + in email address is incorrectly sanitised&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/forge-ui-components/issues/59&quot;&gt;Table does not sort correctly when empty fields are present&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/929&quot;&gt;4xx Errors not shown in App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1076&quot;&gt;Inconsistent errors returned from the API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-launcher/issues/77&quot;&gt;Module install not working on windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1038&quot;&gt;Avatar lettering is mis-allinged when only rendering 1 character&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/968&quot;&gt;it.only is not prohibited&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/966&quot;&gt;No feedback when an API error occurs editing user&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1040&quot;&gt;Start action is available on a running project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Jozefik&quot;&gt;Jozefik&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/1082&quot;&gt;Adding limits to admin panel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome community involvement in what we&#39;re building. If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE1&quot;&gt;Sign up for FlowFuse-Managed Premium&lt;/a&gt; with this link or at the checkout enter the code &lt;strong&gt;RELEASE1&lt;/strong&gt; to get your first project free for a month. As an open source project you can also use &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;FlowFuse-Community&lt;/a&gt; for free, forever.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our managed &lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse&lt;/a&gt; is already running 1.0. Upgrade your project Stacks to the latest version to make sure you get all the latest changes.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/flowforge-1-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Customers of FlowFuse Cloud can raise a ticket by emailing support@flowfuse.com&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/10/db-migration-01/</id>
        <title>Scheduled maintenance: Database encryption October 2022</title>
        <summary>Moving to encrypted PostgreSQL storage</summary>
        <updated>2022-10-18T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/10/db-migration-01/"/>
        <author><name>Ben Hardill</name></author>
        <content type="html">&lt;p&gt;As part of an on-going security &lt;a href=&quot;https://flowfuse.com/platform/security/#data-at-rest&quot;&gt;review&lt;/a&gt; of the FlowFuse Cloud offering we discovered that the backend database was not using encrypted storage. In keeping with industry best practices we plan to migrate the database to a new instance using encrypted at rest storage.&lt;/p&gt;
&lt;h2 id=&quot;impact&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/db-migration-01/#impact&quot;&gt;Impact&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Customers&#39; Node-RED instances will remain running, though any features that depend on FlowFuse will not operate as expected during the migration. This includes user sessions, project and team management, as well as the project nodes for inter-project communication.&lt;/p&gt;
&lt;p&gt;Self-hosted installations are unaffected by this change.&lt;/p&gt;
&lt;h2 id=&quot;when&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/db-migration-01/#when&quot;&gt;When&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The migration will be on 26 October 2022 at 22:00 UTC and is expected to take under 2 hours. The platform will be available as soon as the migration is complete.&lt;/p&gt;
&lt;p&gt;We will post updates during the migration period to our Twitter account &lt;a href=&quot;https://twitter.com/flowforgeinc&quot;&gt;@FlowFuseInc&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/10/ff-docker-gcp/</id>
        <title>Install FlowFuse Docker on Google Cloud</title>
        <summary>Step by step instructions to get FlowFuse Docker running on Google Cloud</summary>
        <updated>2022-10-14T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/10/ff-docker-gcp/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;As part of our preparations for FlowFuse 1.0 we have been testing various real world scenarios to see where we can add to our documentation and where we might be able to improve our releases to make the install process easier for users. As a benefit of that testing we have been able to hone these installation processes and we wanted to share one of those with you today.&lt;/p&gt;
&lt;p&gt;In this first of three articles, we are going to run through the process for installing FlowFuse on Google Cloud Platform (GCP) within a virtual machine (VM) using Docker.&lt;/p&gt;
&lt;p&gt;We have set ourselves the goal of delivering a production environment. We want this installation benefit from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Email alerts (emails to users when they are added to teams etc)&lt;/li&gt;
&lt;li&gt;HTTPS access to the install&lt;/li&gt;
&lt;li&gt;FlowFuse &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#device&quot;&gt;Device&lt;/a&gt; deployment via the included MQTT server that comes in our Docker build&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will follow up with a second article covering the process of getting HTTPS running then we will close out the series by covering how to use key features of FlowFuse including &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#device&quot;&gt;Devices&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;A domain name - We&#39;ve registered flowforge-demo.com to demonstrate these steps&lt;/li&gt;
&lt;li&gt;A DNS provider - Our Domain registrar provides a basic DNS service for free&lt;/li&gt;
&lt;li&gt;A GCP account - Google will often give you free service credits on sign up so setting up FlowFuse on GCP should not cost you anything for at least a few weeks&lt;/li&gt;
&lt;li&gt;An email provider which will allow SMTP connections to send email - To manage users on your FlowFuse platform you will need to be able to send emails to them. We have used a Google Workspace account for this purpose&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;gcp-vm-creation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#gcp-vm-creation&quot;&gt;GCP VM Creation&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Create a GCP account, once logged in navigate to Compute Engine then VM Instances. Select Create Instance you should now be &lt;a href=&quot;https://console.cloud.google.com/compute/instancesAdd?project&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Give your instance a name, select a Region and Zone. I have found that the default machine configuration works fine but depending on your project you may wish to change the resources.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the interface for creating GCP VM&quot; alt=&quot;&amp;quot;Screenshot showing the interface for creating GCP VM&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/1.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You now need to allow access to your FlowFuse installation from the internet. In the Firewall section tick Allow HTTP traffic and Allow HTTPS traffic.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the firewall section in the interface for creating a GCP VM&quot; alt=&quot;&amp;quot;Screenshot showing the firewall section in the interface for creating a GCP VM&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/2.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Next up, assign a static IP address to the VM. Click Advanced options, then Networking. Now scroll down until you see Network interfaces and click on default to expand that section. In External IPv4 address select Create IP Address, give it a name than press Reserve.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the network section in the interface for creating a GCP VM&quot; alt=&quot;&amp;quot;Screenshot showing the network section in the interface for creating a GCP VM&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/3.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Once you have reserved your IP it will be shown in the External IPv4 address field, write it down as we will need it later to create the DNS records. Our IP address was 34.125.156.130.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing your reserved IP in the External IPv4 address field&quot; alt=&quot;&amp;quot;Screenshot showing your reserved IP in the External IPv4 address field&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/4.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You are now ready to create and boot your VM, scroll to the bottom of the page and press Create. It can take a minute or two for the VM to be ready to use.&lt;/p&gt;
&lt;h1 id=&quot;dns-set-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#dns-set-up&quot;&gt;DNS Set Up&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So that you can run FlowFuse on your newly created GCP VM you will need to set up 2 DNS records. These records are slightly different to what is suggested in the FlowFuse install docs. We were keen to be able to run other services on this domain so we set up the following records.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing interface for setting DNS&quot; alt=&quot;Screenshot showing interface for setting DNS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/5.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;DNS changes need to propagate, and depending on your DNS provider, ISP, and other factors, this can take anywhere between a few seconds to 4 hours. Our’s were in place very quickly. To validate the DNS records you can use &lt;code&gt;dig&lt;/code&gt; on either a Mac or Linux.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing output of the dig command&quot; alt=&quot;Screenshot showing output of the dig command&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/6.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The DNS records are set to the IP record we noted down earlier, so we&#39;re good to continue.&lt;/p&gt;
&lt;h1 id=&quot;flowfuse-docker-installation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#flowfuse-docker-installation&quot;&gt;FlowFuse Docker Installation&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The next step is to install Docker on our GCP VM. If you return to GCP you should see that your VM is now up and running, you can now click on SSH to connect to your VM. This will open up a browser based SSH session to your VM.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing access to SSH in GCP&quot; alt=&quot;Screenshot showing access to SSH in GCP&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/7.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Once you have a Secure Shell (SSH) session open, the first step is to install Docker using the following commands.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get update&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install &#92;
   ca-certificates &#92;
   curl &#92;
   gnupg &#92;
   lsb-release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sudo mkdir -p /etc/apt/keyrings&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &#92;
  &amp;quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian &#92;
  $(lsb_release -cs) stable&amp;quot; | sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get update&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can read a lot more detail about what each these commands actually do &lt;a href=&quot;https://docs.docker.com/engine/install/debian/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;download-flowfuse%E2%80%99s-latest-docker-build&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#download-flowfuse%E2%80%99s-latest-docker-build&quot;&gt;Download FlowFuse’s latest Docker build&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The next step is to get the codebase for FlowFuse onto your VM, to do so you will need to run the following commands. Please note that we are working with our 0.10.0 build, you will need to update the version number in the commands below if you are working with a newer build.&lt;/p&gt;
&lt;p&gt;Use curl to download the files we need.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo curl -L https://github.com/FlowFuse/docker-compose/archive/refs/tags/v0.10.1.tar.gz -o v0.10.1.tar.gz&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Make the directory where we will store FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo mkdir /opt/flowforge&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Uncompress FlowFuse and save it to the directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo tar zxf v0.10.1.tar.gz --directory /opt/flowforge&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You should now have all the code you need for FlowFuse in the directory &lt;code&gt;/opt/flowforge/docker-compose-0.10.1&lt;/code&gt;, it should look something like this.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing directory listing for FlowFuse&quot; alt=&quot;&amp;quot;Screenshot showing directory listing for FlowFuse&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/8.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h1 id=&quot;configure-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#configure-flowfuse&quot;&gt;Configure FlowFuse&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We can now configure FlowFuse on your VM. We are going to need to edit two files. Firstly we need to switch into the directory where we just placed FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cd /opt/flowforge/docker-compose-0.10.1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then we need to edit the flowforge.yml file, we&#39;re using Nano to do that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo nano /opt/flowforge/docker-compose-0.10.1/etc/flowforge.yml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;At the top of the file you need to update the domain and base_url to match your domain&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing domain configuration in flowforge.yml&quot; alt=&quot;&amp;quot;Screenshot showing domain configuration in flowforge.yml&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/9.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Next we will need to edit the Email Configuration section to match your SMTP provider. Set enabled to true then add in the details provider by your email provider. For example in this case I am using our Google Workspace account.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing email configuration in flowforge.yml&quot; alt=&quot;&amp;quot;Screenshot showing email configuration in flowforge.yml&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/10.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Finally, you need to update the &lt;code&gt;public_url&lt;/code&gt; for your mqtt broker to match your DNS record.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing MQTT configuration in flowforge.yml&quot; alt=&quot;&amp;quot;Screenshot showing MQTT configuration in flowforge.yml&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/11.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can now save and close that file, in Nano you can do that by pressing ‘control x’ then ‘y’ then the Return key.&lt;/p&gt;
&lt;p&gt;Now we need to edit the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. We will use Nano again to do that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo nano /opt/flowforge/docker-compose-0.10.1/docker-compose.yml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We need to edit the file to add in to the domain as follows.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing virtual hosts configuration in docker-compose.yml&quot; alt=&quot;&amp;quot;Screenshot showing virtual hosts configuration in docker-compose.yml&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/12.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Save and exit from that file, in Nano you can do that by pressing ‘control x’ then ‘y’ then the Return key.&lt;/p&gt;
&lt;h1 id=&quot;start-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/10/ff-docker-gcp/#start-flowfuse&quot;&gt;Start FlowFuse&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We are now ready to start up FlowFuse for the first time, to do so we will use the following command.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo docker compose -p flowforge up -d&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The build process will take a few minutes, once it’s completed let’s make sure all the docker containers are running.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo docker ps&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;Docker PS output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/13.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You should see 4 running Docker containers.&lt;/p&gt;
&lt;p&gt;If everything went well you should now be able to access your FlowFuse server via the DNS record you created.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;FF Login page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/14.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Nice, you now have a working instance of FlowFuse running on GCP but remember that all traffic is currently running on HTTP so we still have some work to do.&lt;/p&gt;
&lt;p&gt;In the next article we will cover how to add HTTPS support to this FlowFuse installation.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/10/community-news-09/</id>
        <title>Community News September 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-10-07T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/10/community-news-09/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what’s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/&quot;&gt;&lt;strong&gt;FlowFuse 0.10&lt;/strong&gt;&lt;/a&gt;
Version 0.10 was released on 30th September. Our latest release includes some great new features, quality of life improvements and bug fixes. Notable additions included the ability to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/893&quot;&gt;Secure your HTTP endpoints&lt;/a&gt;, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/657&quot;&gt;Add read-only users to your projects&lt;/a&gt; and &lt;a href=&quot;https://flowfuse.com/docs/cloud/introduction/#ip-addresses&quot;&gt;use our static IP address for outbound connections&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 0.10 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/&quot;&gt;blog post&lt;/a&gt;, on our &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v0.10.0&quot;&gt;GitHub release page&lt;/a&gt; and on our &lt;a href=&quot;https://youtube.com/watch?v=mjR1iiEFiBg&quot;&gt;Youtube channel&lt;/a&gt;. We’d also love for more of you to get involved in the development of FlowFuse, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/blob/main/CONTRIBUTING.md&quot;&gt;contributions to the code&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;bug reports&lt;/a&gt; are really appreciated.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;&lt;strong&gt;Node-RED Con 2022&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We are happy to again be involved in Node-RED con. The event is being held online on 7th October, with content for both English and Japanese speakers including our colleagues Nick O&#39;Leary and Sam Machin. You can find out more on the &lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;Node-RED Con website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowforge.com/team/&quot;&gt;&lt;strong&gt;FlowFuse Team News&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We are currently recruiting &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004&quot;&gt;NodeJS Developers&lt;/a&gt;, if you’re interested in joining our team please &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004#app&quot;&gt;apply here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are also looking for a &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4687876004&quot;&gt;PeopleOps Manager&lt;/a&gt; to help us grow our team. You can &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4687876004#app&quot;&gt;apply here&lt;/a&gt; for that position.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hackster.io/user102774/fight-fire-wild-fire-prediction-using-tinyml-df7572&quot;&gt;&lt;strong&gt;Forest Fire Alerts Using ML, IOT and Node-RED&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
This fascinating project came up a few days ago and we wanted to share it with you all. The concept is to use a mesh network of IoT devices to monitor various indicators of potential and current wildfires and report data back to the relevant authorities. The system will use ML to predict wildfire risk levels and hopefully send warnings before a fire actually starts. The two developers &lt;a href=&quot;https://linkedin.com/in/zainmfd/&quot;&gt;Muhammed&lt;/a&gt; and &lt;a href=&quot;https://linkedin.com/in/salmanfarisvp/&quot;&gt;Salman&lt;/a&gt; are planning to use Node-RED to manage the reporting of fires to the authorities.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;&lt;strong&gt;Try FlowFuse for Free&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As a thank you for reading our newsletters we’d like to offer you a free, small project for one month on FlowFuse when you create a new team. To get this discount please follow &lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE010&quot;&gt;this link&lt;/a&gt; or use the code RELEASE010 when on the payment page after creating a new team.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/09/flowforge-010-released/</id>
        <title>FlowFuse 0.10 released</title>
        <summary>Secure HTTP end points, Read-only users and Static outbound IPs</summary>
        <updated>2022-09-30T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/09/flowforge-010-released/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Secure your HTTP endpoints, create read-only users in your teams and use our static IP address for outbound traffic&lt;/p&gt;
&lt;p&gt;Keep reading for the details of what&#39;s in this release or you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 0.10 is now available. The next release of the FlowFuse application containing new features, a number of improvements, and bug fixes. Keep reading for a promotion code to get your first month free on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/578&quot;&gt;Secure HTTP Endpoints&lt;/a&gt;
We&#39;ve added the ability for you to secure your HTTP endpoints. You can now control who can access Dashboards or API endpoints you create in FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/657&quot;&gt;Read-only Users&lt;/a&gt;
We&#39;ve added a new user role for Read-only access. This will allow users to login to your FlowFuse project and view the Node-RED flows without them being able to edit anything.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/docs/cloud/introduction/#ip-addresses&quot;&gt;Static Outbound IP Addresses&lt;/a&gt;
We&#39;ve updated FlowFuse Cloud so that all outbound traffic from your projects now comes from a single IP address. When trying to access a remote resource such as a database it is often a requirement for the IP address the traffic comes from to be fixed.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made a number of improvements to the overall experience of running FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allow both key and component in a ff-data-table column definition &lt;a href=&quot;https://github.com/FlowFuse/forge-ui-components/issues/43&quot;&gt;#43&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Default Stack and Templates &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/989&quot;&gt;#989&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Provide platform containers and base stack container for administrators &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/917&quot;&gt;#917&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/917&quot;&gt;Provide platform containers and base stack container for administrators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/983&quot;&gt;User names can be same (but different case)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/463&quot;&gt;User list not refreshing after changing user details&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/986&quot;&gt;Navigating directly to a device page gets the wrong team selected&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/941&quot;&gt;Node-RED Isn&#39;t ready when FlowFuse app says it is running following a project restart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/923&quot;&gt;Invitations left for deleted teams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/1024&quot;&gt;Following email verification link twice throws error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/21&quot;&gt;Agent does not log stderr from the Node-RED process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/948&quot;&gt;On Kubernetes project names can not start with a number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/930&quot;&gt;When creating projects stack options do not wrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/979&quot;&gt;Save button in admin user-edit dialog doesn&#39;t close dialog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/911&quot;&gt;Setting UI doesn&#39;t allow me to update settings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Pezmc&quot;&gt;Pezmc&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/949&quot;&gt;Add device count and project counts by type to admin&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ArshErgon&quot;&gt;ArshErgon&lt;/a&gt; for their work on &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/977&quot;&gt;Update vue component name for NoVerifiedEmail.vue&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome the community involvement in what we&#39;re building. If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create?code=RELEASE010&quot;&gt;Sign up for FlowFuse Cloud&lt;/a&gt; with this link or at the checkout enter the code &lt;strong&gt;RELEASE010&lt;/strong&gt; to get your first project free for a month.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 0.10 and the stacks updated. Upgrade your project stacks to the latest version to make sure you get all the latest changes.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-010-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Customers of FlowFuse Cloud can raise a ticket by emailing support@flowfuse.com&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/09/static-ips/</id>
        <title>Static Outbound IP Addresses</title>
        <summary>Static IP addresses are here for your FlowFuse Cloud projects’ outbound connections</summary>
        <updated>2022-09-27T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/09/static-ips/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;On Friday last week we updated FlowFuse Cloud to use a static IP address for outbound traffic. This will allow you to predict which IP address your traffic will come from for example when traversing a firewall or accessing a remote database.&lt;/p&gt;
&lt;p&gt;You will need to manually suspend then start each of your projects (a restart will not move your projects to the fixed IP address). Once that action is completed all outbound connections will come from one of our static IP address.&lt;/p&gt;
&lt;p&gt;Any inbound traffic should still use the hostname assigned to each of your projects, you cannot use our IP address to route http traffic to your projects.&lt;/p&gt;
&lt;p&gt;You can view our IP address in the &lt;a href=&quot;https://flowfuse.com/docs/cloud/introduction/#ip-addresses&quot;&gt;Docs&lt;/a&gt; section of our website.&lt;/p&gt;
&lt;p&gt;If you’d like to stay up to date with our latest releases you can do so on &lt;a href=&quot;https://flowfuse.com/blog/&quot;&gt;our blog&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/09/community-news-08/</id>
        <title>Community News August 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-09-16T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/09/community-news-08/"/>
        <author><name>Rob Marcer</name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what’s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/&quot;&gt;&lt;strong&gt;FlowFuse 0.9&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Version 0.9 was released on 1st September. Our latest release includes some great new features, quality of life improvements and bug fixes. Notable additions included the ability to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/893&quot;&gt;suspend your projects&lt;/a&gt;, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/856&quot;&gt;login with your email&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/774&quot;&gt;define custom paths for your dashboards&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to learn more about what else was included in 0.9 you can do so on our &lt;a href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/&quot;&gt;blog post&lt;/a&gt;, on our &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/releases/tag/v0.9.0&quot;&gt;GitHub release page&lt;/a&gt; and on our &lt;a href=&quot;https://www.youtube.com/watch?v=d23Pmyc0k7I&quot;&gt;Youtube channel&lt;/a&gt;. We’d also love for more of you to get involved in the development of FlowFuse, &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/blob/main/CONTRIBUTING.md&quot;&gt;contributions to the code&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;bug reports&lt;/a&gt; are really appreciated.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;&lt;strong&gt;Node-RED Con 2022&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We are happy to again be involved in Node-RED con. The event is being held online on 7th October, with content for both English and Japanese speakers. You can find out more on the &lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;Node-RED Con website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/team/&quot;&gt;&lt;strong&gt;FlowFuse Team News&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
We’d like to welcome Rob Marcer to the FlowFuse team. Rob has joined as our Developer Educator, he&#39;s going to work to help you get the best value from FlowFuse by developing our documentation and community support.&lt;/p&gt;
&lt;p&gt;We are also recruiting for &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004&quot;&gt;NodeJS Developers&lt;/a&gt;, if you’re interested in joining our team please &lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4463977004#app&quot;&gt;apply here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/Docker/status/1559919666721693699?t=QBzGGzY2kJ12Z5aoi1QPTA&quot;&gt;&lt;strong&gt;Official Node-RED Docker Image Passes Milestone&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Docker has &lt;a href=&quot;https://twitter.com/Docker/status/1559919666721693699?t=QBzGGzY2kJ12Z5aoi1QPTA&quot;&gt;announced&lt;/a&gt; that the Node-RED Docker image has now been downloaded over 100 million times. They have also created a &lt;a href=&quot;https://www.docker.com/blog/build-retail-store-items-detection-system-no-code-ai/?utm_campaign=2022-08-17-brnd-nocode&amp;amp;utm_medium=social&amp;amp;utm_source=twitter&quot;&gt;guide to using Node-RED&lt;/a&gt; to Build and Deploy a Retail Store Items Detection System Using No-Code AI Vision at the Edge. We think it’s worth a read.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wokwi.com/&quot;&gt;&lt;strong&gt;Simulating IOT Projects in Your Browser&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
While not directly related to FlowFuse we’ve enjoyed wasting a little too much time looking at the simulated IOT projects on &lt;a href=&quot;https://wokwi.com/&quot;&gt;Wokwi&lt;/a&gt;. The &lt;a href=&quot;https://wokwi.com/projects/328451800839488084&quot;&gt;Simon Game with Score&lt;/a&gt; project is a little too addictive.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;&lt;strong&gt;Try FlowFuse for Free&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
As a thank you for reading our newsletters we’d like to offer you a free, small project for one month on FlowFuse when you create a new team. To get this discount please use the code RELEASE09 when on the payment page after creating a new team.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/09/flowforge-09-released/</id>
        <title>FlowFuse 0.9 released</title>
        <summary>Suspended projects, login with email and Team Types</summary>
        <updated>2022-09-01T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/09/flowforge-09-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Suspend your projects when you don&#39;t need them, login with either your username or email, and introducing Team Types&lt;/p&gt;
&lt;p&gt;Keep reading for the details of what&#39;s in this release our you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 0.9 is now available. The next release of the FlowFuse application containing new features, a number of improvements, and bug fixes. Keep reading for a promotion code to get your first month free on FlowFuse Cloud.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/893&quot;&gt;Suspend Projects&lt;/a&gt;
Sometimes you want to put a project to one side for a while, maybe your development has stalled or you&#39;re waiting on something external to be ready. Perhaps you don&#39;t need it to be running all the time. With the 0.9 release we&#39;ve added the ability to suspend a project. Once suspended, your flows are safely stored in the platform database, but Node-RED isn&#39;t running and the project doesn&#39;t consume any resources. In FlowFuse Cloud we do not charge you for suspended projects - you only pay when the project is running.
Your project will be there ready to start back up when you need it with just one click.
Remember that any context data or anything written to the filesystem will not persist through a restart or a suspend of a project.&lt;/p&gt;
&lt;p&gt;Alongside this change, we&#39;ve removed the option to &#39;stop&#39; a project. That option would only stop Node-RED, but the underlying container would still be running, consuming resources. With Node-RED 3.0 adding the ability to stop the flows, but still be able to edit them, that provides a much better user experience.
You can still restart the Node-RED process from the Forge app as before for example when you have updated a package in your flows.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/733&quot;&gt;Team Types&lt;/a&gt;
We&#39;ve introduced another concept into the platform with this release. Team Types will allow us to offer more advanced features to teams on FlowFuse Cloud. You won&#39;t see much difference in this release but it allows us to build on in future releases.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/695&quot;&gt;PostHog Analytics&lt;/a&gt;
We&#39;ve changed the analytics tooling integrated into the platform. With this release, we&#39;ve deprecated the use of Plausible Analytics as it didn&#39;t quite provide the sort of insight we wanted. We now integrate with &lt;a href=&quot;https://posthog.com/&quot;&gt;PostHog&lt;/a&gt;. They share our ethos and approach to open source and self hosting - something you can take advantage of if you&#39;re running your own FlowFuse platform.
For FlowFuse Cloud, the data is sent to our PostHog account so we can better understand how the platform is being used. If you&#39;re running your own instance, the information is only captured if you configure it with your own PostHog instance details - it does not send any data back to us.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/856&quot;&gt;Login with email&lt;/a&gt;
A common problem that we&#39;ve seen from users is trying to login with their email address instead of their username. As of 0.9 you can now enter either at the login screen.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/774&quot;&gt;Custom Dashboard Path&lt;/a&gt;
If you are using the Node-RED Dashboard set of nodes, you can now change the path where the dashboard will be served from. The default is still &lt;code&gt;/ui&lt;/code&gt; but you can now move that onto &lt;code&gt;/&lt;/code&gt; or anything else. This is helpful when migrating existing projects over to FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made a number of improvements to the overall experience of running FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improvements to the FlowFuse Theme &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/883&quot;&gt;#883&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Upper-case characters in Project Names &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/546&quot;&gt;#546&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Password reset requests are logged&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/773&quot;&gt;#773&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Admin can manually verify users email &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/692&quot;&gt;#902&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/875&quot;&gt;Cannot edit template settings&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/nr-project-nodes/issues/10&quot;&gt;Project Link Nodes Appear in CE Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/nr-project-nodes/issues/14&quot;&gt;Project Link Nodes MQTT Connection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-theme/issues/19&quot;&gt;Theme shows white characters on white background&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/27&quot;&gt;Changing Project on device doesn&#39;t remove old modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/30&quot;&gt;Device Agent and Node-RED use different time in logs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/bonanitech&quot;&gt;Bonantech&lt;/a&gt; for his work &lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-theme/commit/30e21a3777dc3438ef206157ee9110728011f59c&quot;&gt;cleaning up the theme CSS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As an open-source project, we welcome the community involvement in what we&#39;re building. If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowforge.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#try-it-out&quot;&gt;Try it out&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up for FlowFuse Cloud&lt;/a&gt; and at the checkout enter the code &lt;strong&gt;RELEASE09&lt;/strong&gt; to get your first project free for a month.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 0.9 and the stacks updated. Upgrade your project stacks to the latest version and start using the Project Link nodes now.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/09/flowforge-09-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Customers of FlowFuse Cloud can raise a ticket by emailing support@flowfuse.com&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/08/community-news-06/</id>
        <title>Community News July 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-08-11T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/08/community-news-06/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/&quot;&gt;FlowFuse 0.8 &lt;/a&gt;&lt;br /&gt;
Version 0.8 was released, notable features include the new Project Link nodes for sharing data between projects, and the ability to stop and start flows within Node-RED.
We&#39;ve updated the format of our release posts as well to detail all the user facing changes, from new Features through to small improvements and bugs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tomshardware.com/how-to/raspberry-pi-pico-w-node-red&quot;&gt;Raspberry Pi Pico with Node-RED&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://twitter.com/biglesp&quot;&gt;Les Pounder&lt;/a&gt; Has published a great tutorial on communicating with the new &lt;a href=&quot;https://www.raspberrypi.com/products/raspberry-pi-pico/&quot;&gt;Raspberry Pi Pico W&lt;/a&gt; and Node-RED. He shows you how to capture data from an environmental sensor then display this on a dashboard.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/07/new-projecttype/&quot;&gt;Medium Projects&lt;/a&gt;&lt;br /&gt;
We&#39;ve added a second size of project to FlowFuse Cloud. A bigger project type with more resources available to it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.golioth.io/how-to-use-node-red-to-control-iot-devices-on-golioth/&quot;&gt;Using Node-RED to control IoT Devices on Golioth&lt;/a&gt;&lt;br /&gt;
Our friends at &lt;a href=&quot;https://golioth.io/&quot;&gt;Golioth&lt;/a&gt; have published an article on how to use Node-RED to control and process data from IoT Devices connected to their platform.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discourse.nodered.org/t/node-red-2-2-3-and-3-0-2-released/66018&quot;&gt;Node-RED 3.0.2 and 2.2.3&lt;/a&gt;&lt;br /&gt;
Node-RED 3.0.2 has been released fixing some bugs in the 3.0.0 release, The Node-RED 2.x stream has also had a maintenance release with many of the fixes in 3.0 back-ported. As usual these are already available as stacks on FlowFuse Cloud.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/08/flowforge-08-released/</id>
        <title>FlowFuse 0.8 released</title>
        <summary>Inter-Project Communication, Default Teams, and realtime device management.</summary>
        <updated>2022-08-04T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/08/flowforge-08-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Easily pass messages between your projects on the cloud or devices, UX improvements, and more.&lt;/p&gt;
&lt;p&gt;Keep reading for  the details of whats in this release our you can watch our 1 minute roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 0.8 is now available. The next release of the FlowFuse application containing new features, a number of improvements, and bug fixes.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/662&quot;&gt;Project Link Nodes&lt;/a&gt;
We&#39;ve introduced our first custom FlowFuse nodes to the palette of new projects. The Project Link nodes allow you to easily pass data between different projects within the same team.
These projects can be running in the cloud or on devices, with the communication powered by our own internal MQTT broker.
Try these out today on FlowFuse Cloud by creating a new project or updating your existing project&#39;s stack. There&#39;s more information in the &lt;a href=&quot;https://github.com/FlowFuse/nr-project-nodes/blob/main/README.md&quot;&gt;README&lt;/a&gt; for the nodes.
For local installs of FlowFuse, the nodes are only available with an Enterprise Edition license.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the message being sent from one project to another using project link nodes&quot; alt=&quot;&amp;quot;Screenshot showing the message being sent from one project to another using project link nodes&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ProjectLink.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/839&quot;&gt;Start &amp;amp; Stop Flows&lt;/a&gt;
Node-RED 3.0 &lt;a href=&quot;https://nodered.org/blog/2022/07/14/version-3-0-released#editing-stopped-flows&quot;&gt;introduced a new feature&lt;/a&gt; that allows you to stop your flows from processing requests while still being able to work in the editor and deploy changes. We&#39;ve now enabled this feature within FlowFuse for projects running a Node-RED 3.x stack.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/298&quot;&gt;Default Team&lt;/a&gt;
If you are a member of multiple teams you can now set your preferred default saving you from having to change teams each time you log in.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made a number of improvements to the overall experience of running FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Devices now communicate to the Forge application over MQTT instead of polling &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/754&quot;&gt;#754&lt;/a&gt;. You&#39;ll need to update your Device Agent to the latest version to take advantage of this.&lt;/li&gt;
&lt;li&gt;The table views have had a major overhaul allowing you to sort and search items &lt;a href=&quot;https://github.com/FlowFuse/forge-ui-components/issues/28&quot;&gt;#28&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If the application receives an error you now see a notification in the UI. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/771&quot;&gt;#771&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Verification email page has been cleaned up &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/718&quot;&gt;#718&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The initial Thank-you page has been cleaned up &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/648&quot;&gt;#648&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/793&quot;&gt;Logo Distorted in Safari&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/729&quot;&gt;LocalFS Install doesn&#39;t check for Build Tools&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/842&quot;&gt;Users with Expired passwords can create teams&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/790&quot;&gt;Click-jacking Vulnerability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/824&quot;&gt;Users with can create teams without verifying email&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-storage/issues/17&quot;&gt;Occasional Timeout when deploying flows&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/833&quot;&gt;Notification of member deletion contains internal ID&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/334&quot;&gt;Pressing Enter in the Team Delete modal triggers cancel&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/751&quot;&gt;Node-RED Isn&#39;t ready when Forge app says it is running (Docker)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#contributors&quot;&gt;Contributors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;d like the thank the following for their contributions to this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/HaroldPetersInskipp&quot;&gt;HaroldPetersInskipp&lt;/a&gt; helped &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/812&quot;&gt;updating our documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Steveorevo&quot;&gt;Steveorevo&lt;/a&gt; also &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/pull/818&quot;&gt;updated our documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an open-source project, we welcome the community involvement in what we&#39;re building. If you&#39;re interested in contributing, checkout our &lt;a href=&quot;https://flowfuse.com/docs/contribute/&quot;&gt;guide in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 0.8 and the stacks updated. Upgrade your project stacks to the latest version and start using the Project Link nodes now.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/08/flowforge-08-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Customers of FlowFuse Cloud can raise a ticket by emailing support@flowfuse.com&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/07/new-projecttype/</id>
        <title>Introducing Medium Projects on FlowFuse Cloud</title>
        <summary>A bigger project with more resources</summary>
        <updated>2022-07-22T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/07/new-projecttype/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;We&#39;ve added a second size of project to FlowFuse Cloud. A bigger project type with more resources available to it.&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://flowforge.com/blog/2022/07/flowforge-07-released/&quot;&gt;0.7 release&lt;/a&gt; introduced the concept of Project Types. This allows platforms to provide different sizes of projects, varying the memory/cpu or features available within a given type.&lt;/p&gt;
&lt;p&gt;Today we&#39;ve put this feature to work on FlowFuse Cloud by introducing the new &lt;strong&gt;Medium Project&lt;/strong&gt; type.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the new stack selection feature&quot; alt=&quot;&amp;quot;Screenshot showing the new stack selection feature&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/project-type.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Medium projects have 3 times the resources of the existing Small type, allowing for more complex flows and larger message objects. This will be useful to business users looking to process complex sets of data.&lt;/p&gt;
&lt;p&gt;Our Medium project is priced at $50 a month and we&#39;ll be adding new features to this project type in the coming months to further enhance the value of this new tier.&lt;/p&gt;
&lt;p&gt;We don&#39;t currently support directly upgrading a project between types, but that is in the &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/595&quot;&gt;plan for the future&lt;/a&gt;. In the meantime, you can use the &#39;Export Project&#39; feature on a project&#39;s settings tab to copy it over into a new Medium type project.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/07/community-news-06/</id>
        <title>Community News June 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-07-19T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/07/community-news-06/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/&quot;&gt;FlowFuse 0.7 &lt;/a&gt;&lt;br /&gt;
We&#39;ve shipped the next version of FlowFuse, features in this release include the ability to Rollback a project to a previous snapshot, setting environment variables for a specific device and we&#39;ve begun to unify the experience between the Forge app and the Node-RED editor with our own Node-RED theme.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodered.org/blog/2022/07/14/version-3-0-released&quot;&gt;Node-RED 3.0 Released &lt;/a&gt;&lt;br /&gt;
Node-RED 3.0 Has been officially released, there are a lot of improvements in the user experience of the editor, with new menus and junctions. There&#39;s also the ability to stop your flows while you can continue to edit and deploy. Take a look at the blog post for all the details. This is now the default stack on FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discourse.nodered.org/t/node-red-flows-on-esp8266-and-esp32/64345&quot;&gt;Node-RED for Microcontrollers&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://twitter.com/phoddie&quot;&gt;Peter Hoddie&lt;/a&gt; of &lt;a href=&quot;https://moddable.com/&quot;&gt;Moddable&lt;/a&gt; Has released some early &lt;a href=&quot;https://github.com/phoddie/node-red-mcu&quot;&gt;work&lt;/a&gt; on getting the Node-RED runtime to execute a flow on a microcontroller like the ESP32. It&#39;s still very early days so don&#39;t expect to be building flows directly on the MCU, and the number of nodes that are supported is limited, but this is an interesting development for Node-RED in the IoT space.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.papercall.io/nrcon2022&quot;&gt;Node-RED Con CFP&lt;/a&gt;&lt;br /&gt;
A reminder about Node-RED Con and the call for papers, submissions close at the end of July so get your proposals in now.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/07/flowforge-07-released/</id>
        <title>FlowFuse 0.7 released</title>
        <summary>Rollbacks, Device Environment Variables and a FlowFuse Theme</summary>
        <updated>2022-07-07T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/07/flowforge-07-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Rollback projects to a previous snapshot, improvements in using Devices, and more.&lt;/p&gt;
&lt;p&gt;Keep reading for  the details of whats in this release our you can watch our 1 min roundup video of the new release above.&lt;/p&gt;
&lt;p&gt;We&#39;re pleased to announce version 0.7 is now available. the next release of the FlowFuse application.&lt;/p&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/587&quot;&gt;Rollback&lt;/a&gt;
FlowFuse is about running Node-RED at any scale, part of that scale is having multiple users collaborate on the same project. When you are collaborating with people it&#39;s important to be able to go back in time to a known working state. As part of that we are introducing rollbacks, this means that you can now take a snapshot of your project at a point in time and then make changes safe in the knowledge that you can rollback to that previous snapshot if you need to.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/680&quot;&gt;Device Environment Variables&lt;/a&gt;
In the last release we introduced the concept of devices. We&#39;re already learning from how these are used and one feature we&#39;ve added in 0.7 is Device Environment Variables. You have been able to set Environment Variables at the project level but when deploying a snapshot to multiple devices you may want to override these values for each device, for example to set a site ID. With device specific variable users are enabled to differentiate based on the context in their flows.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowforge-nr-theme/&quot;&gt;FlowFuse Theme&lt;/a&gt;
Now that we have a stronger visual identity in the Forge application we have continued that work through to the Node-RED editor. If you create or upgrade a project with a Node-RED 3.0 stack you will see a different theme in the editor. It&#39;s still very much Node-RED but just has some subtle hints to tie it back to the FlowFuse application. We will continue to iterate on this to further integrate the experience between FlowFuse and Node-RED in both directions.
&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Screenshot showing the FlowFuse theme when the Node-RED 3.0 stack is selected&quot; alt=&quot;&amp;quot;Screenshot showing the FlowFuse theme when the Node-RED 3.0 stack is selected&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-07-theme.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/380&quot;&gt;ProjectTypes&lt;/a&gt;
The introduction of ProjectTypes is a way to group Stacks together that share common characteristics - such as memory/cpu limits, or the availability of particular features. In platforms with billing enabled, such as our own FlowFuse Cloud, the ProjectTypes can have different price points set on them. Within FlowFuse Cloud, you&#39;ll see we&#39;ve introduced the Small ProjectType - which applies to all existing projects on the platform.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/694&quot;&gt;Stack Versions&lt;/a&gt;
This allows an admin to link different stacks together in their lineage. This allows administrators to nudge users to new Node-RED versions or upgrade pre-installed dependencies when running in a container environment. Any users with projects on an old version will be prompted that there is an update available, making it even easier to stay up to date with Node-RED versions when you build your flows on FlowFuse.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/#improvements&quot;&gt;Improvements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve made a number of improvements to the overall experience of running FlowFuse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Team Switch menu has been moved to a more prominent position in the interface, this also makes it easier to see how to create a new team. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/616&quot;&gt;#616&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Notifications have had an overhaul, you will now see waiting invites on all pages. &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/515&quot;&gt;#515&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you are running your own copy of FlowFuse you can now see the version details in the admin pages &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/655&quot;&gt;#655&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Device polling is no longer an INFO level message  filling the log on your devices &lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/10&quot;&gt;#10&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bug-fixes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/#bug-fixes&quot;&gt;Bug Fixes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve fixed the following bugs in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/7&quot;&gt;Devices now listen on all Interfaces allowing you to run local http servers&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/device-agent/issues/7&quot;&gt;Solved an issue where a device gets an error  unknown device&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/507&quot;&gt;The Audit Log in the Forge app displays the correct IP when a user logs in to Node-RED&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/507&quot;&gt;Resolved an issue with devices downloading snaphots from legacy stacks&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/735&quot;&gt;Fixed an error where objects in the Node-RED log would hang the log page&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/745&quot;&gt;Next Billing Date is now shown correctly&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/689&quot;&gt;Fixed a bug where the loading page would flash during polling&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 0.7 - ready for
you to try out rollbacks and the new theme.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/07/flowforge-07-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.
That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;Customers of FlowFuse Cloud can raise a ticket by emailing support@flowfuse.com&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/06/flowforge-06-released/</id>
        <title>FlowFuse 0.6 released</title>
        <summary>Adding Devices to the platform</summary>
        <updated>2022-06-19T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/06/flowforge-06-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Node-RED is well known for its role in IoT solutions - which often means running
flows on devices.&lt;/p&gt;
&lt;p&gt;This was something we always wanted to support in FlowFuse and with this release
we&#39;re taking the next steps in that direction.&lt;/p&gt;
&lt;h3 id=&quot;devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/#devices&quot;&gt;Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This release includes the first alpha release of the &lt;a href=&quot;https://github.com/FlowFuse/device-agent&quot;&gt;FlowFuse Device Agent&lt;/a&gt;. This is a small piece of node.js software that can be
installed on a device, such as a Raspberry Pi. It connects back to the FlowFuse
platform to get the Node-RED flows it should be running.&lt;/p&gt;
&lt;p&gt;This builds on the work we added in 0.5 that lets you register the device,
generate credentials for it and pick which Project in your team it should be assigned
to.&lt;/p&gt;
&lt;p&gt;It makes it super simple to start developing your flows in FlowFuse and push them
out to a group of devices with a couple clicks.&lt;/p&gt;
&lt;p&gt;There&#39;s plenty of work still to come on the Devices feature. Under the covers
it uses an HTTP polling approach to check for updates. That was a pragmatic choice
to get something working - but it isn&#39;t our long term strategy. We&#39;ll be working
towards a more IoT-native MQTT/WebSocket appoach in the coming releases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/device-agent/introduction/&quot;&gt;Devices documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/446&quot;&gt;Epic #446 - Devices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;snapshots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/#snapshots&quot;&gt;Snapshots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This release adds the ability to create Snapshots of your projects. These are
point-in-time backups of your project&#39;s flows, credentials and settings.&lt;/p&gt;
&lt;p&gt;With this release we support &lt;em&gt;creating&lt;/em&gt; snapshots and pushing them to devices.&lt;/p&gt;
&lt;p&gt;We don&#39;t have the ability to revert a project back to a previous snapshot, but
that will come soon.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/snapshots/&quot;&gt;Snapshot documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/587&quot;&gt;Story #587 - Snapshot/Rollback&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/#other-updates&quot;&gt;Other updates&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Beyond these headline features, there are a number of smaller, but just as useful
items in this release.&lt;/p&gt;
&lt;p&gt;We&#39;ve continued with the rebranding work started in 0.5 with some more improvements
to the overall UX of the platform. Little touches like placeholder loading graphics
give the UI a more responsive feel.&lt;/p&gt;
&lt;p&gt;When you log out of the platform we now also automatically log you out of any
Node-RED editor sessions you have open.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://app.flowfuse.com/&quot;&gt;FlowFuse Cloud&lt;/a&gt; is already running 0.6 - ready for
you to start creating snapshots and adding devices right now.&lt;/p&gt;
&lt;p&gt;If you installed a previous version of FlowFuse and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/06/community-news-05/</id>
        <title>Community News May 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-06-17T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/06/community-news-05/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.&lt;/p&gt;
&lt;p&gt;If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/06/flowforge-06-released/&quot;&gt;FlowFuse 0.5 AND 0.6&lt;/a&gt;&lt;br /&gt;
We&#39;ve had two releases since our last newsletter, there are a lot of related features between them.
We introduced a new design for the forge application which aligns with the branding on our website.
We&#39;ve added &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#device&quot;&gt;Devices&lt;/a&gt;, allowing you to run and manage your Node-RED projects on your own hardware, this is ideal for applications that need to connect to either sensor data or specialist hardware deployed outside the cloud.
We added a new concept as part of this work, &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#snapshot&quot;&gt;Snapshots&lt;/a&gt; allow you to take a point in time copy of your project, today that can then be deployed to one or more devices but we have plans to expand this concept for things like &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/587&quot;&gt;rolling back&lt;/a&gt; a project to a previous point in time.
&lt;a href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/&quot;&gt;0.5&lt;/a&gt; Introduced the capabilities of copying a project or certain parts of it, allowing for scenarios like having multiple environments for Development and Production.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discourse.nodered.org/t/node-red-3-0-0-beta-3-released/64027&quot;&gt;Node-RED 3.0.0-beta-3&lt;/a&gt;&lt;br /&gt;
The Node-RED 3.0 beta releases continue as the project is getting very close to the full release in the coming weeks, We&#39;ll be making it availble on FlowFuse cloud very soon.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kazuhitoyokoi.medium.com/creating-custom-node-from-subflow-in-node-red-ce52cc42bbba&quot;&gt;Creating custom node from subflow in Node-RED&lt;/a&gt;&lt;br /&gt;
One of the contributors to Node-RED, Kazuhito Yokoi wrote a nice tutorial on how to turn a subflow into a custom node.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCbBzP8NZbv3WDtlt4UouA-g&quot;&gt;YouTube Channel&lt;/a&gt;&lt;br /&gt;
Joe has been busy creating short videos to present FlowFuse and our key concepts, these will start to appear on our YouTube channel, so please like and subscribe!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.42flows.tech/blog/why-have-we-decided-to-implement-visa-direct-api-for-node-red/&quot;&gt;Visa Direct in Node-RED&lt;/a&gt;&lt;br /&gt;
The folks over at 42flows use Node-RED in a financial and banking context, they&#39;ve published an article about integrating with the Visa payments APIs&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.papercall.io/nrcon2022&quot;&gt;Node-RED Con CFP&lt;/a&gt;&lt;br /&gt;
A reminder about Node-RED Con and the call for papers, submissions close at the end of July but don&#39;t wait until the last minute to submit your proposal.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/05/sign-up-for-flowforge-cloud/</id>
        <title>FlowFuse open for everybody</title>
        <summary>Sign up and start a new Node-RED project within a minute!</summary>
        <updated>2022-05-25T09:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/05/sign-up-for-flowforge-cloud/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;FlowFuse wants to enable everyone to build workflows in Node-RED. Since announcing
&lt;a href=&quot;https://flowforge.com/blog/2022/02/announcing-flowforge-cloud/&quot;&gt;FlowFuse Cloud&lt;/a&gt;
two months ago we&#39;ve had a waiting list for users to sign up to. That allowed us
to control the pace we were bringing new users onto the platform, learning what
is needed to scale up our platform and continue to improve our first user experience.&lt;/p&gt;
&lt;p&gt;Today we have removed the waiting list. Anyone can sign up to FlowFuse and start a
new Node-RED project in under a minute!&lt;/p&gt;
&lt;div class=&quot;max-w-md m-auto&quot;&gt;
  &lt;a class=&quot;ff-btn ff-btn--primary&quot; href=&quot;https://app.flowfuse.com/account/create&quot;&gt;Sign up&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what-we-offer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/sign-up-for-flowforge-cloud/#what-we-offer&quot;&gt;What we offer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Besides the sub minute time to start a new Node-RED project, there&#39;s many more
features our offering includes. Two we&#39;d like to highlight.&lt;/p&gt;
&lt;p&gt;To start our blog highlight reel: Collaboration. FlowFuse allows you to work
with a team on your flows. There&#39;s the ability to create multiple users, each
with their own credentials that can alter the flows on Node-RED, and it&#39;s
execution environment like for example the &lt;a href=&quot;https://flowforge.com/docs/user/envvar/&quot;&gt;environments variables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Furthermore, &lt;a href=&quot;https://flowforge.com/docs/user/changestack&quot;&gt;stacks&lt;/a&gt;. These allow
a user to select the execution environment for their Node-RED project. For example; the
Node-RED version being used. Combined with the ability for one to copy a project
to a new stack, this allows FlowFuse users to copy their project to the Node-RED
3.0-beta stack to validate their solutions will continue to work on the new release
without disrupting their main project.&lt;/p&gt;
&lt;h2 id=&quot;our-roadmap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/sign-up-for-flowforge-cloud/#our-roadmap&quot;&gt;Our roadmap&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently we&#39;re working towards our 0.6 release. The main feature of this release
will be support for Devices. This will allow you to send a snapshot of a project
to a Node-RED instance running outside of the FlowFuse platform and update the flows
remotely. Remote devices will run our &lt;a href=&quot;https://github.com/FlowFuse/device-agent&quot;&gt;agent&lt;/a&gt;
to communicate with the FlowFuse Cloud project.&lt;/p&gt;
&lt;p&gt;While the first iteration will be considered an Alpha release, by shipping early and often, it lets us get
welcome feedback from our users and the wider community - helping to shape the future direction.
It also allows users to start validating the feature for their own proof of concept projects.&lt;/p&gt;
&lt;p&gt;Over the next few months we&#39;re continuing to drive development of the platform
across a number of areas - including further improvements to the Device feature.
But also looking at new Enterprise-ready features, such as Single-Sign On integration
and more tools to make collaboration even easy.&lt;/p&gt;
&lt;p&gt;We intend to grow our offering so that FlowFuse remains the best way to run
Node-RED.&lt;/p&gt;
&lt;p&gt;Stay informed by registering for our newsletter!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/05/flowforge-05-released/</id>
        <title>FlowFuse 0.5 released</title>
        <summary>Bringing a new look to the platform</summary>
        <updated>2022-05-12T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/05/flowforge-05-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;The cycle continues with our next regularly scheduled release, bringing a fresh
new look to the platform.&lt;/p&gt;
&lt;p&gt;Since joining the team, Joe has been hard at work bringing a more consistent
design language to what we&#39;re doing. This release brings a lot of his hardwork
to the platform itself.&lt;/p&gt;
&lt;p&gt;There&#39;s more to be done on the individual pages of the platform, but this
gives us a solid framework to build on.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/ff-05-dashboard.png&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/430&quot;&gt;Epic #430 - Rebrand Forage App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;copying-projects&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/#copying-projects&quot;&gt;Copying Projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One of the usage scenarios we want to support is having an easy way to have separate
test and production environments. The previous release added the ability to configure
environment variables on individual projects.&lt;/p&gt;
&lt;p&gt;This release unlocks the next piece of the puzzle - making it easy to copy flows
between projects.&lt;/p&gt;
&lt;p&gt;The Project settings page has two new options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy Project lets you create a complete copy of the project.&lt;/li&gt;
&lt;li&gt;Export to existing project lets you copy over selected aspects of the project
over to another project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases, you get to pick what parts of the project should be copied.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/268&quot;&gt;Epic #268 - Export Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/271&quot;&gt;Story #271 - Duplicate Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/272&quot;&gt;Story #272 - Export to Existing Project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;improve-billing-information&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/#improve-billing-information&quot;&gt;Improve Billing Information&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ve been getting some great feedback from the users of FlowFuse Cloud. One of the
areas we identified as needing some more clarity was around the point users are
asked to setup their billing information.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/563&quot;&gt;Story #563 - Improve Information on billing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;edge-devices&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/#edge-devices&quot;&gt;Edge Devices&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whilst we always want to deliver new functionality to end users in each release,
sometimes bits of work don&#39;t fit naturally into a single four week iteration.&lt;/p&gt;
&lt;p&gt;That&#39;s the case here with some of the preliminary work we&#39;ve done to introduce
the idea of Edge Devices to the platform.&lt;/p&gt;
&lt;p&gt;The goal here is to provide a way to easily deploy and manage Node-RED projects
on remote devices.&lt;/p&gt;
&lt;p&gt;This release introduces a bunch of work to the core app and front-end to begin
introducing the concept of a Device. It includes the basic workflows for registering
a device on the platform and being able to assign it to a team.&lt;/p&gt;
&lt;p&gt;The whole feature is hidden behind a feature flag so users on FlowFuse Cloud won&#39;t
see any of this quite yet.&lt;/p&gt;
&lt;p&gt;The next release will introduce the Edge Agent piece of this - the bit that runs
on devices.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/446&quot;&gt;Epic #446 - Devices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you installed a previous version of FlowFuse  and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/05/flowforge-05-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/05/community-news-04/</id>
        <title>Community News April 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-05-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/05/community-news-04/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/&quot;&gt;FlowFuse 0.4&lt;/a&gt;&lt;br /&gt;
The next release has enabled us to offer multiple versions of Node-RED along with adding more features to help you configure your Node-RED projects.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discourse.nodered.org/t/node-red-3-0-0-beta-1-released/62124&quot;&gt;Node-RED 3.0.0-beta-1&lt;/a&gt;&lt;br /&gt;
The first beta for Node-RED 3.0.0 has been published, there&#39;s some exciting improvements on UI in the editor to make designing your flows even easier.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/05/node-red-3-beta-stack/&quot;&gt;Node-RED Beta on FlowFuse&lt;/a&gt;&lt;br /&gt;
As promised in out 0.4 announcement, we&#39;ve made the beta available to our users on FlowFuse as a separate stack, this is just one way that we&#39;re able to demonstrate the flexibility you get from running Node-RED on FlowFuse.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.cisco.com/meraki/build/exploring-meraki-and-spark-apis-with-node-red/&quot;&gt;Cisco &amp;amp; Node-RED&lt;/a&gt;&lt;br /&gt;
The team at Cisco DevNet published some great guides on using Node-RED to manage both your Meraki Access points and to integrate with WebEx Teams, they&#39;ve also produced a handy &lt;a href=&quot;https://blogs.cisco.com/developer/helloworldlowcodenodered01&quot;&gt;starter guide&lt;/a&gt; for those that are new to Node-RED&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nrcon.nodered.org/&quot;&gt;Node-RED Con 2022&lt;/a&gt;&lt;br /&gt;
Our friends in the Node-RED Japan User Group have run a number of successful Node-RED conferences over the last few years. This year, we&#39;re joining forces with them to bring the event to a wider audience. The &lt;a href=&quot;https://www.papercall.io/nrcon2022&quot;&gt;Call for Papers&lt;/a&gt; is open now and we&#39;d love to see your submissions.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/05/node-red-3-beta-stack/</id>
        <title>Node-RED 3.0 Beta Stack</title>
        <summary>Try out the next major Node-RED release</summary>
        <updated>2022-05-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/05/node-red-3-beta-stack/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;The first beta of Node-RED 3.0 is here and FlowFuse is ready for you to try it out.&lt;/p&gt;
&lt;p&gt;When we released &lt;a href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/&quot;&gt;FlowFuse 0.4&lt;/a&gt; last month we talked about allowing users to select the stack their project runs on.
Until now we&#39;ve only offered one stack which has been the latest Node-RED release (2.2.2).&lt;/p&gt;
&lt;p&gt;Yesterday the first beta of Node-RED 3.0 was &lt;a href=&quot;https://discourse.nodered.org/t/node-red-3-0-0-beta-1-released/62124&quot;&gt;released&lt;/a&gt;, so as of today we have added a choice of stacks to FlowFuse Cloud. You can stick with the &lt;em&gt;Default&lt;/em&gt; and use Node-RED 2.2.2 or if you want to try out the beta you can select &lt;em&gt;Node-RED-3.0.0-beta-1&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;source type=&quot;image/jpeg&quot; srcset=&quot;&quot; sizes=&quot;100vw, 100vw&quot; /&gt;&lt;img title=&quot;Selecting the beta Stack&quot; alt=&quot;Selecting the beta Stack&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://flowfuse.com/img/beta_stack.gif&quot; width=&quot;undefined&quot; height=&quot;undefined&quot; /&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;FlowFuse is the best way to run multiple Node-RED instances at different versions. Beta releases are exciting to try out, but you don&#39;t want to risk your production applications with an early upgrade. FlowFuse makes it easy to create a new project to try things out.&lt;/p&gt;
&lt;p&gt;We&#39;ll continue to update the stack choice with each beta when they are released.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/04/flowforge-04-released/</id>
        <title>FlowFuse 0.4 released</title>
        <summary>Getting ready for Node-RED 3.0</summary>
        <updated>2022-04-14T12:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/04/flowforge-04-released/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;This release of the FlowFuse adds a seemingly small, but significant new feature.&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://nodered.org/about/releases/&quot;&gt;Node-RED 3.0 fast approaching&lt;/a&gt; we&#39;ve been making sure we are ready to support this.&lt;/p&gt;
&lt;h3 id=&quot;upgrading-node-red&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#upgrading-node-red&quot;&gt;Upgrading Node-RED&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The goal of FlowFuse is to be the best way to run Node-RED at any scale, whether that&#39;s many users or many instances. Node-RED is a constantly developing as a platform and therefore part of running Node-RED is also upgrading the version you are running.&lt;/p&gt;
&lt;p&gt;With the 0.4 release today we&#39;ve made that super simple in FlowFuse. Last month we introduced the concept of &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#stack&quot;&gt;Project Stacks&lt;/a&gt;. One of the key elements of a Stack was the version of Node-RED in use. Initially this may have seemed fairly basic, when you create a new project you usually want to use the latest version of Node-RED. However what happens when a new version is released and you have an existing project?
Now you can change the stack that a project is running on, which in turn will change the version of Node-RED. This is a simple process from the project settings, it only requires a short period of downtime while the project restarts on the new stack, typically around 10-15 seconds.&lt;/p&gt;
&lt;p&gt;Our driver to get this feature into the 0.4 release is the approaching release of Node-RED 3.0, now we know that we can be ready to offer our users Node-RED 3.0 as soon as it is released.&lt;/p&gt;
&lt;p&gt;We will also be making available the Beta&#39;s of Node-RED 3.0 within FlowFuse Cloud,  this becomes a great way to test out the new features without having to touch your own environments.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/288&quot;&gt;Story #288 - Change Stacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/changestack/&quot;&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;environment-variables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#environment-variables&quot;&gt;Environment Variables&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another key new feature we are introducing is the ability to set and manage environment variables within your projects.
Environment Variables are a key tool when building applications as they allow you to to separate the configuration of your system from the logic in the code. Even in Low-Code platforms this is an important design pattern. Environment variables are fully integrated into &lt;a href=&quot;https://flowfuse.com/docs/user/concepts/#template&quot;&gt;Templates&lt;/a&gt; that we introduced last month so they can be set both at the platform level or on an individual project.
Our plans for the next release will make these even more useful as we introduce the ability to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/271&quot;&gt;duplicate a project&lt;/a&gt; and then modify those variables for the new project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/225&quot;&gt;Story #225 - Project Environment Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowfuse.com/docs/user/envvar/&quot;&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;there&#39;s-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#there&#39;s-more&quot;&gt;There&#39;s more&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are many more improvements in this release, such as the ability to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/239&quot;&gt;Set the timezone&lt;/a&gt; your project is running in, we&#39;ve also been iterating on our billing experience as we&#39;ve welcomed the first paying customers to FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;Finally we&#39;re very happy that we&#39;ve had our first external contribution to the code base, as an Open Core company we believe strongly that Open Source lives at the heart of everything we do.
We would like to say a big thank-you to &lt;a href=&quot;https://fakocodes.netlify.app/&quot;&gt;Fakorede Damilola Idris&lt;/a&gt; for his work on fixing a &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/424&quot;&gt;bug&lt;/a&gt; in the UI.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#getting-started-with-flowfuse&quot;&gt;Getting started with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The documentation provides a guide for &lt;a href=&quot;https://flowfuse.com/docs/install/&quot;&gt;installing FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t played with FlowFuse yet, here&#39;s a more complete walk-through
of the platform:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;YYZDx8n17Ys&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you installed a previous version of FlowFuse  and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/#upgrading-flowfuse&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/04/flowforge-04-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our regular release cycle puts the next release on Thursday 12th May.
We will be building on features in the last few releases around managing your projects and using templates, we&#39;re also  setting the foundations of our work to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/446&quot;&gt;manage Node-RED on your own devices running at the Edge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more information, check out the &lt;a href=&quot;https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/&quot;&gt;announcement blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also sign up to our general mailing list below if you want to hear more
about the work we&#39;re doing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/04/community-news-03/</id>
        <title>Community News March 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-04-05T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/04/community-news-03/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/&quot;&gt;New Website&lt;/a&gt;&lt;br /&gt;
Some of you may have noticed the new design on our website, this is the first step in our more refined corporate identity, the same look will be coming to the FlowFuse application &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/430&quot;&gt;soon.&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/&quot;&gt;FlowFuse 0.3&lt;/a&gt;&lt;br /&gt;
The latest release introduced 2 new concepts, Templates and Stacks, with these we are starting to show the value of the FlowFuse platform allowing you to easily manage the Node-RED settings and versions used by your projects.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.opto22.com/support/resources-tools/videos/video-introduction-to-json-for-node-red/&quot;&gt;Intro to JSON for Node-RED&lt;/a&gt;&lt;br /&gt;
Our friends over at Opto 22 published a handy guide to JSON and how it works in Node-RED, great introduction for new builders and a good refresher for seasoned pros.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/04/flowforge-accepting-customers/</id>
        <title>FlowFuse is accepting customers now</title>
        <summary>We&#39;re starting to onboard users from the waitlist</summary>
        <updated>2022-04-04T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/04/flowforge-accepting-customers/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;A year ago our CTO, Nick O&#39;Leary, &lt;a href=&quot;https://flowfuse.com/blog/2021/04/first-deploy/&quot;&gt;introduced FlowFuse&lt;/a&gt;.
Since then major milestones have been achieved. As we grow as a company, important
steps are taken. Today we make another very important step; we&#39;re accepting our
first customers.&lt;/p&gt;
&lt;p&gt;A few weeks ago our product was nearly in a state where it could support customers,
when that was the case, we &lt;a href=&quot;https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/&quot;&gt;opened up our waitlist&lt;/a&gt;.
The waitlist has been growing daily and now we&#39;re ready to start inviting those
users onto the platform. The first
lucky few users are being added today, and each working day for the foreseeable
future we&#39;ll continue onboarding users. New users will receive an email from our
team with their login details and can start creating new workflows with Node-RED
minutes after.&lt;/p&gt;
&lt;p&gt;While the source code of FlowFuse is &lt;a href=&quot;https://github.com/FlowFuse/flowfuse&quot;&gt;available&lt;/a&gt;,
there&#39;s a chance you&#39;re unfamiliar with what has been built around Node-RED.
With FlowFuse, our intent is to build a platform to aid with colaboration of
flows in Node-RED. The first steps to our vision include a managed Node-RED
instance to connect virtually any online service. Multiple users will have
access to the same flows and can collaborate. Further, once Node-RED 3.0 has
been released, the platform will provide a pain-free way to upgrade and keep
your projects up to date. There&#39;s many more exciting features right around the
corner on our &lt;a href=&quot;https://flowfuse.com/changelog/&quot;&gt;roadmap&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/03/flowforge-03-released/</id>
        <title>FlowFuse 0.3 released</title>
        <summary>Moving towards the launch of FlowFuse Cloud</summary>
        <updated>2022-03-17T01:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/03/flowforge-03-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;The FlowFuse 0.3 release brings us closer to the launch of FlowFuse Cloud.
Find out more about what&#39;s in this new release.&lt;/p&gt;
&lt;p&gt;This release of the FlowFuse platform brings some significant new features that
will underpin more of what is to come.&lt;/p&gt;
&lt;h3 id=&quot;project-stacks-%26-templates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#project-stacks-%26-templates&quot;&gt;Project Stacks &amp;amp; Templates&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When we think about what a makes a Project inside FlowFuse, the simple answer
is Node-RED.&lt;/p&gt;
&lt;p&gt;The more complete answer is: a version of Node-RED, a version of Node.js, some
memory, some CPU and a bunch of Node-RED settings to customise the instance.&lt;/p&gt;
&lt;p&gt;In a platform like FlowFuse, it&#39;s important to have the tools to manage all
of these things.&lt;/p&gt;
&lt;p&gt;This is where Project Stacks and Template come in.&lt;/p&gt;
&lt;p&gt;A Project Stack defines the underlying characteristics of the Node-RED process -
or the container it is running in. For example, with our Local deployment model,
it defines the version of Node-RED to use and how much memory the process should
try to use. In our container based deployment models, the stack identifies the
container to use for the project, along with memory and CPU limits.&lt;/p&gt;
&lt;p&gt;In a future release, this will be the way we will support upgrading the version
of Node-RED a project is using - and doing so in a well managed way. An Administrator
will be able to create a new Stack containing the new version of Node-RED.
Project owners will then be able to update their projects to use the new Stack -
at a time that is convenient to them.&lt;/p&gt;
&lt;p&gt;A Project Template is more about how the Node-RED instance is configured - exposing
the options a user would traditional modify in their Node-RED settings file.
With this release, we&#39;re not exposing a lot of settings as the focus has been
more on the underlying Template concept. But it will be the basis for gradually
exposing more options for customisation in the future.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/285&quot;&gt;Epic #285 - Project Stacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/141&quot;&gt;Epic #141 - Project Templates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;billing-integration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#billing-integration&quot;&gt;Billing Integration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With our open core philosophy, the heart of the FlowFuse platform is open source
and available under the Apache 2 license for anyone to use.&lt;/p&gt;
&lt;p&gt;But the plan was always to have certain features that were licensed separately.&lt;/p&gt;
&lt;p&gt;This release brings the first of those features - Stripe Billing Integration. This
feature brings the ability to require a Team to have a Stripe Billing agreement
in place and to be able to charge on a per-project basis within that Team.&lt;/p&gt;
&lt;p&gt;Being able to charge is an important feature for any commercial platform, and
with our own FlowFuse Cloud launching soon, we needed to get this feature in
place today.&lt;/p&gt;
&lt;p&gt;We&#39;ve structured the code in the repository and updated the LICENSE file to make it
very clear what parts of the code base are &lt;em&gt;not&lt;/em&gt; covered by the Apache 2 license.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/224&quot;&gt;Epic #224 - Billing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;getting-started-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#getting-started-with-flowfuse&quot;&gt;Getting started with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The documentation provides a guide for &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/tree/main/docs&quot;&gt;installing FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t played with FlowFuse yet, here&#39;s a more complete walk-through
of the platform:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;YYZDx8n17Ys&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you installed FlowFuse 0.1 or 0.2 and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/03/flowforge-03-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our regular release cycle puts the next release on Thursday 14th April.&lt;/p&gt;
&lt;p&gt;We&#39;re still in planning stage for the release, but we&#39;ll also be beginning to invite
people from the waiting list to sign-up to FlowFuse Cloud.&lt;/p&gt;
&lt;p&gt;For more information, check out the &lt;a href=&quot;https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/&quot;&gt;annoucement blog post&lt;/a&gt;.
You can also sign up to our general mailing list below if you want to hear more
about the work we&#39;re doing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/03/community-news-02/</id>
        <title>Community News February 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-03-02T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/03/community-news-02/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the FlowFuse newsletter, a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community.
If you&#39;ve got something that you&#39;d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/&quot;&gt;Announcing FlowFuse Cloud&lt;/a&gt;&lt;br /&gt;
We are excited to announce FlowFuse Cloud, a hosted Node-RED as a service offering and today we are opening the waitlist.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/02/flowforge-02-released/&quot;&gt;FlowFuse 0.2&lt;/a&gt;&lt;br /&gt;
We continue to iterate with our 4 weekly releases of the FlowFuse platform.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discourse.nodered.org/t/node-red-2-2-2-released/58606&quot;&gt;Node-RED 2.2.2&lt;/a&gt;&lt;br /&gt;
The 2.2 release of Node-RED (last month) has received 2 maintenance releases to fix bugs with  duplicate wires in the editor and MQTT.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/02/welcome-joe/&quot;&gt;New Team Members&lt;/a&gt;&lt;br /&gt;
FlowFuse is now up to 6 people, Joe Pavitt has joined the team&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4312861004&quot;&gt;We still are Hiring&lt;/a&gt;&lt;br /&gt;
We&#39;re looking for the next member of our team, If you&#39;re a Node.JS developer and want to work with us take a look at the link.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/</id>
        <title>Announcing FlowFuse Cloud</title>
        <summary>Hosting your Node-RED, so you don&#39;t have to.</summary>
        <updated>2022-02-23T19:44:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;As an open core company, anyone is free to &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/tree/9219e81399eaf52fb0ee5573707a52f5520fbfdd/docs/install&quot;&gt;download and install&lt;/a&gt;
our platform. In many cases this is a great solution, it
allows for custom setups in your own environment. We know this isn&#39;t for everyone
though, some people just want to start building with Node-RED without having to manage their servers.&lt;/p&gt;
&lt;p&gt;We are excited to announce FlowFuse Cloud, a hosted
Node-RED as a service offering and today we are opening the waitlist.&lt;/p&gt;
&lt;p&gt;Our waitlist captures your email, and we&#39;ll reach out to you on that address once your account is created.&lt;/p&gt;
&lt;h3 id=&quot;starting-operations&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/02/announcing-flowforge-cloud/#starting-operations&quot;&gt;Starting operations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After having released v0.2 recently, we&#39;re now working on v0.3 that will include
a user flow for &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/224&quot;&gt;billing&lt;/a&gt;.
When that work has been done and deployed people on the waitlist will slowly be invited to the platform.
Currently that&#39;s scheduled for April 1st, no joke, although it could happen either sooner
or later.
More details on the exact pricing will be availble nearer the time.&lt;/p&gt;
&lt;p&gt;Once you are invited you will be able to;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create multiple Node-RED projects hosted on flowforge.cloud,&lt;/li&gt;
&lt;li&gt;Invite team members to collaborate on those projects,&lt;/li&gt;
&lt;li&gt;And many more features will automatically become availble with each new release.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/02/flowforge-02-released/</id>
        <title>FlowFuse 0.2 released</title>
        <summary>Keeping the releases flowing of our open platform for Node-RED</summary>
        <updated>2022-02-17T01:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/02/flowforge-02-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Four weeks have passed since our initial release of FlowFuse, and we&#39;re happy
to release v0.2 today as we continue moving forward and evolve the platform.&lt;/p&gt;
&lt;p&gt;There aren&#39;t lots of headline features in this release to tell you about as a lot
of the work has been on the internals, as well as responding to some of the early
feedback from the community.&lt;/p&gt;
&lt;p&gt;Features like improving the test framework, and building a database migration
framework may not sound too exciting to the end user, but they are critical pieces
when build a platform that needs to be stable and easy to upgrade.&lt;/p&gt;
&lt;p&gt;We&#39;ve also been doing work to get our own instance of the platform running in the
Cloud - and figuring out how to automate as much of that as possible. Aside
from being a key way to test the platform, it helps validate the work we&#39;re doing
for when others come to run it in that way. It also lays the ground work for our
own cloud service we&#39;ll be sharing more about in the coming days.&lt;/p&gt;
&lt;p&gt;The full change-log for the core of the platform is available &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/blob/v0.2.0/CHANGELOG.md&quot;&gt;on GitHub&lt;/a&gt;.
But with a further 15 repositories containing different components, each with its
own change-log, we&#39;re still thinking about how best to share a single view of the
updates.&lt;/p&gt;
&lt;h3 id=&quot;getting-started-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/02/flowforge-02-released/#getting-started-with-flowfuse&quot;&gt;Getting started with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The documentation provides a guide for &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/tree/main/docs&quot;&gt;installing FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t played with FlowFuse 0.1 yet, here&#39;s a more complete walk-through
of the platform:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;YYZDx8n17Ys&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;upgrading-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/02/flowforge-02-released/#upgrading-flowfuse&quot;&gt;Upgrading FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you installed FlowFuse 0.1 and want to upgrade, our documentation provides a
guide for &lt;a href=&quot;https://flowfuse.com/docs/upgrade/&quot;&gt;upgrading FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/02/flowforge-02-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;#flowfuse&lt;/code&gt; channel on the &lt;a href=&quot;https://nodered.org/slack&quot;&gt;Node-RED Slack workspace&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/02/flowforge-02-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our regular release cycle puts the next release on Thursday 17th March. We&#39;ve
got some key features planned in this release around &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/141&quot;&gt;Project Templates&lt;/a&gt; and &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues/285&quot;&gt;Stacks&lt;/a&gt; -
which will underpin how you can customise Node-RED within FlowFuse.&lt;/p&gt;
&lt;p&gt;We&#39;ll also have some exciting news to share about our own hosted service you&#39;ll
be able to sign-up for.&lt;/p&gt;
&lt;p&gt;Sign up to the mailing list below if you want to hear more about the work we&#39;re
doing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/02/use-case-solar-afloat/</id>
        <title>Using Node-RED to keep Solar PV afloat</title>
        <summary>How spb sonne used Node-RED with a renewable energy solution</summary>
        <updated>2022-02-09T09:26:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/02/use-case-solar-afloat/"/>
        <author><name>ZJ van de Weg</name></author>
        <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/krishnanravichandran/&quot;&gt;Krisnan Ravichandran&lt;/a&gt; works
for &lt;a href=&quot;https://www.sbp.solar/&quot;&gt;spb sonne&lt;/a&gt;, a engineering consultancy for renewable
energy. Within the company he is part of the engineering effort on the
&lt;a href=&quot;https://www.sbp.de/en/news/goembhal-sbp-sonnes-pioneering-floating-pv-system/&quot;&gt;Gömbhal&lt;/a&gt;
project, creating a floatation device for solar panels.&lt;/p&gt;
&lt;p&gt;In this post, he shares his experiences of using Node-RED.&lt;/p&gt;
&lt;p&gt;Currently there’s a prototype deployed in Hungary, while the company is located
in Stuttgart: “We’re remotely monitoring the installation. There are over 40
sensors that all connect to an ADAM-6717, Compact Intelligent Gateway. When the
data is acquired we leverage Node-RED flows that maintain the structure, monitor
performance, and provide reporting back to our offices.&lt;/p&gt;
&lt;p&gt;Node-RED is embedded in the ADAM 6717, it was very new to me. I was already
experienced in programming, mainly Python, and within a month I felt very
comfortable and productive in Node-RED. Understanding programming is useful,
though not a necessity.&lt;/p&gt;
&lt;p&gt;Building and improving flows I did on my own through trial-and-error, as well
as a lot of times through help on the &lt;a href=&quot;https://discourse.nodered.org/&quot;&gt;Node-RED Forum&lt;/a&gt;.
The community is helpful and welcoming to new users. Now I maintain multiple
flows with very different purposes. Some track temperature,
irradiation wind-speed, direction, tilt and wave height; to ensure the floating
PV installation remains floating. Other sensors are connected to actuators
through flows that control pressure.&lt;/p&gt;
&lt;p&gt;We do have some challenges; the ADAM 6717 contained an older version of Node-RED.
This raised questions around security and maintenance, as our Node-RED version
isn’t updated to a newer version in an easy manner. It also hampers training a
bit because documentation might reference an API or node for a flow that’s just
not the same on older versions.&lt;/p&gt;
&lt;p&gt;However, I’d choose Node-RED again, it’s well known as well as easy to learn.
Furthermore I found it very versatile.”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Thanks to Krisnan for sharing his story. If you have a Node-RED story for us
to share, please get in touch via &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/02/welcome-joe/</id>
        <title>Welcome Joe</title>
        <summary></summary>
        <updated>2022-02-08T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/02/welcome-joe/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;Today we welcome Joe Pavitt (&lt;a href=&quot;https://twitter.com/joepavitt3d&quot;&gt;@joepavitt3d&lt;/a&gt;) as
our new Head of UX &amp;amp; Design. This is a key role that will help deliver the awesome
user experience of the FlowFuse platform.&lt;/p&gt;
&lt;p&gt;Joe has a passion for user experience, data visualisation and creativity in
technology. He joins us having been at IBM for 9 years where he specialised in
building bespoke, first of a kind experiences in IBM&#39;s Emerging Technology and
Research teams.&lt;/p&gt;
&lt;p&gt;We worked together at IBM and I saw first-hand the range and quality of what he
can do. I was super pleased when he agreed to join us and I look forward to
seeing the real impact he&#39;ll have on what we&#39;re building.&lt;/p&gt;
&lt;p&gt;Welcome aboard Joe!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/01/community-news-01/</id>
        <title>Community News January 2022</title>
        <summary>News from the FlowFuse and Node-RED communities</summary>
        <updated>2022-01-28T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/01/community-news-01/"/>
        <author><name></name></author>
        <content type="html">&lt;p&gt;Welcome to the first FlowFuse newsletter, we’re going to publish this as a regular roundup of what`s happening with both FlowFuse and the wider Node-RED community, if you want to receive it via email, sign up for updates at the bottom of the page.
If you’ve got something that you’d like us to share please email &lt;a href=&quot;mailto:contact@flowfuse.com/&quot;&gt;contact@flowfuse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/2022/01/flowforge-01-released/&quot;&gt;FlowFuse 0.1 Released&lt;/a&gt;&lt;br /&gt;
First up we are really pleased to ship the first version of our platform, this is a very early release but hopefully will give you an idea of the direction we’re going in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodered.org/blog/2022/01/27/version-2-2-released&quot;&gt;Node-RED 2.2&lt;/a&gt;&lt;br /&gt;
The next version of Node-RED has been released with new editor features, predefined environment variables and improvements to some of the core nodes. Checkout the blog post and change log for more details.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.golioth.io/building-iot-dashboards-with-golioth-grafana-and-node-red&quot;&gt;Make your IoT data beautiful&lt;/a&gt;&lt;br /&gt;
Ben Mawby wrote a guide on connecting Golioth&#39;s WebSocket endpoints to Grafana using Node-RED and InfluxDB&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sammachin.com/posts/alexaweb-reborn&quot;&gt;Alexa Voice Service on Node-RED&lt;/a&gt;&lt;br /&gt;
Sam Machin rebuilt an app on Node-RED allowing you to talk to Alexa through the browser. And he has published a new &lt;a href=&quot;https://flows.nodered.org/node/@sammachin/node-red-alexa-voice-service&quot;&gt;node&lt;/a&gt; to use the Alexa Voice Service within your own flows.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://flowfuse.com/blog/&quot;&gt;New Team Members&lt;/a&gt;&lt;br /&gt;
We welcomed 2 new members of the FlowFuse team this month &lt;a href=&quot;https://flowfuse.com/blog/2022/01/welcome-zj/&quot;&gt;ZJ&lt;/a&gt; joins as our CEO and &lt;a href=&quot;https://flowfuse.com/blog/2022/01/welcome-steve/&quot;&gt;Steve&lt;/a&gt; has come onboard to work on the Node-RED project&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://boards.greenhouse.io/flowfuse/jobs/4312861004&quot;&gt;We are Hiring&lt;/a&gt;&lt;br /&gt;
We&#39;re looking for the next member of our team, If you&#39;re a Node.JS developer and want to work with us take a look at the link.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/01/flowforge-01-released/</id>
        <title>FlowFuse 0.1 released</title>
        <summary>Making the first release of the platform and transitioning to open development</summary>
        <updated>2022-01-20T01:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/01/flowforge-01-released/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;For an open core company, we haven&#39;t been very open with what we&#39;re doing. That all
changes today with the release of FlowFuse 0.1 and making all of our repositories
public.&lt;/p&gt;
&lt;p&gt;This is a significant step for the company as we look to build a platform around Node-RED.&lt;/p&gt;
&lt;p&gt;The main question we get asked is: &#39;What is FlowFuse?&amp;quot; - which is a very reasonable
question to ask.&lt;/p&gt;
&lt;p&gt;FlowFuse is a platform for managing Node-RED instances at scale. It lets you have
multiple users on the platform, organised into teams to provide proper access control
to individual Node-RED instances, or Projects as we call them.&lt;/p&gt;
&lt;p&gt;With the 0.1 release, we have the basic building blocks of the platform in place.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add multiple users to the platform&lt;/li&gt;
&lt;li&gt;Create teams for those users&lt;/li&gt;
&lt;li&gt;Create Node-RED projects quickly and easily through the platform UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a more complete walk-through of the platform in this early release, you can
watch this video.&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid=&quot;YYZDx8n17Ys&quot; params=&quot;rel=0&quot; style=&quot;width: 704px; height: 100%;&quot; title=&quot;YouTube video player&quot;&gt;&lt;/lite-youtube&gt;&lt;/p&gt;
&lt;h3 id=&quot;getting-started-with-flowfuse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/01/flowforge-01-released/#getting-started-with-flowfuse&quot;&gt;Getting started with FlowFuse&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The documentation provides a guide for &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/tree/main/docs&quot;&gt;installing FlowFuse on a local server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also have drivers for deploying to Docker Compose and Kubernetes based environments
to enable a larger scale of deployment. We&#39;ll have more documentation on those options
in the near future.&lt;/p&gt;
&lt;h3 id=&quot;getting-help&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/01/flowforge-01-released/#getting-help&quot;&gt;Getting help&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you hit any problems with the platform, or have questions to ask, please do
raise an &lt;a href=&quot;https://github.com/FlowFuse/flowfuse/issues&quot;&gt;issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That also includes if you have any feedback or feature requests.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2022/01/flowforge-01-released/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With so much in the plan and lots of exciting features to come, we will have a
regular cycle of releases every four weeks. So you can expect the next release, 0.2,
on Thursday 17th February.&lt;/p&gt;
&lt;p&gt;As we&#39;re only at 0.1 today, there is a lot still to do. We will be following the
principles of &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt; with our releases,
but until we reach 1.0, there may be some disruptive changes along the way.&lt;/p&gt;
&lt;p&gt;Sign up to the mailing list below if you want to hear more about the work we&#39;re
doing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/01/welcome-steve/</id>
        <title>Welcome Steve</title>
        <summary></summary>
        <updated>2022-01-20T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/01/welcome-steve/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;We&#39;re continuing to grow the FlowFuse team with our latest hire; Steve McLaughlin
who is joining our development team.&lt;/p&gt;
&lt;p&gt;Steve is a well known face in the Node-RED community. He is a regular contributor
to the community forum, always happy to help users with their questions.&lt;/p&gt;
&lt;p&gt;He has published a number of very popular nodes, include &lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-buffer-parser&quot;&gt;buffer-parser&lt;/a&gt;,
&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-cron-plus&quot;&gt;cron-plus&lt;/a&gt; and
&lt;a href=&quot;https://flows.nodered.org/node/node-red-contrib-image-tools&quot;&gt;image-tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;He has also made some significant contributions to the core of Node-RED, such as
delivering MQTTv5 support and introducing the Monaco code editor into the heart
of the editor.&lt;/p&gt;
&lt;p&gt;Steve joins us from a background in Industrial IoT in the automative manufacturing
space - experience and knowledge that will be invaluable as we look to growing the
FlowFuse platform.&lt;/p&gt;
&lt;p&gt;Steve will be focussed on the Node-RED side of our activities - helping to continue
the ongoing development and growth of the open source project at the heart of what
FlowFuse is about.&lt;/p&gt;
&lt;p&gt;Welcome aboard Steve!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2022/01/welcome-zj/</id>
        <title>Welcome ZJ</title>
        <summary></summary>
        <updated>2022-01-03T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2022/01/welcome-zj/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;This year the FlowFuse team will grow further, and I&#39;m excited to announce our
newest addition to the team; Zeger-Jan van de Weg (&lt;a href=&quot;https://twitter.com/ZJvandeWeg&quot;&gt;@ZJvandeWeg&lt;/a&gt;).
Zeger-Jan, also known as ZJ, is joining FlowFuse as CEO.&lt;/p&gt;
&lt;p&gt;ZJ previously worked at GitLab where he helped build a vibrant open source
community and we&#39;re thrilled to have him to continue this with the Node-RED
community. Under his supervision the involvement of GitLab in the Git project
grew significantly, allowing Git and GitLab to be successful together. This aligns
well with our vision for FlowFuse:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will only be successful if the whole Node-RED community is successful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As our first non-engineering hire, ZJ will be focussed on growing the business side
of FlowFuse, working on marketing and ongoing business development.&lt;/p&gt;
&lt;p&gt;Welcome aboard ZJ!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2021/05/welcome-ben/</id>
        <title>Welcome Ben</title>
        <summary></summary>
        <updated>2021-05-10T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2021/05/welcome-ben/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;I&#39;m excited to share the news that Ben Hardill (&lt;a href=&quot;https://twitter.com/hardillb&quot;&gt;@hardillb&lt;/a&gt;) is joining FlowFuse as a Senior Engineer.&lt;/p&gt;
&lt;p&gt;I&#39;ve known Ben for many years, having worked together at IBM. He&#39;s been an active member
of the Node-RED community since the start of the project and he published one of
the very first &lt;a href=&quot;https://flows.nodered.org/node/node-red-node-geofence&quot;&gt;3rd party nodes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;He is ever-present on Stack Overflow, to the point where I&#39;ve long since stopped
rushing to respond to questions tagged with &lt;a href=&quot;https://stackoverflow.com/questions/tagged/node-red&quot;&gt;&lt;code&gt;node-red&lt;/code&gt;&lt;/a&gt;
in the full knowledge that he has usually beaten me to it.&lt;/p&gt;
&lt;p&gt;More recently he&#39;s been doing some really interesting work exploring &lt;a href=&quot;https://www.hardill.me.uk/wordpress/2020/10/01/multi-tenant-node-red/&quot;&gt;multi-tenant Node-RED systems&lt;/a&gt; - something we&#39;ll
be continuing at FlowFuse.&lt;/p&gt;
&lt;p&gt;Welcome aboard Ben!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <id>https://flowfuse.com/blog/2021/04/first-deploy/</id>
        <title>Introducing FlowFuse Inc.</title>
        <summary>Building a new low-code development platform around the Node-RED project</summary>
        <updated>2021-04-06T00:00:00Z</updated>
        <link href="https://flowfuse.com/blog/2021/04/first-deploy/"/>
        <author><name>Nick O&#39;Leary</name></author>
        <content type="html">&lt;p&gt;When Dave and I first created &lt;a href=&quot;https://nodered.org/&quot;&gt;Node-RED&lt;/a&gt;, it was a tool to solve a
problem - allowing us to do our day job more effectively when building IoT solutions
for clients. That gave us the means and purpose to create a truly useful platform.&lt;/p&gt;
&lt;p&gt;When it became an open source project, it quickly found an enthusiastic audience that
has seen the community grow beyond our imagination. From both individual users, to a wide
range of companies integrating it into their own products.&lt;/p&gt;
&lt;p&gt;But with that growth, the question in my mind has always been how to take it further
and secure its long term future.&lt;/p&gt;
&lt;p&gt;I wrote on the &lt;a href=&quot;https://nodered.org/blog/2020/10/13/future-plans&quot;&gt;project blog&lt;/a&gt;
last year about the future plans of the project. A key piece of that is its sustainability -
how we can increase the commercial adoption of Node-RED and how we can get more people
contributing back.&lt;/p&gt;
&lt;p&gt;An opportunity presented itself earlier this year that I believe will bring a
step-change to what the Node-RED project is able to achieve.&lt;/p&gt;
&lt;h3 id=&quot;introducing-flowfuse-inc.&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2021/04/first-deploy/#introducing-flowfuse-inc.&quot;&gt;Introducing FlowFuse Inc.&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So today, I&#39;m launching FlowFuse Inc - a new company whose mission is to build a low-coding development
platform fit for the enterprise with Node-RED at its heart.&lt;/p&gt;
&lt;p&gt;Backed by &lt;a href=&quot;https://www.linkedin.com/in/sijbrandij/&quot;&gt;Sid Sijbrandij&lt;/a&gt;, we have funding
in place to create a fully remote team dedicated to an open core model.&lt;/p&gt;
&lt;p&gt;In the short term, this means helping to accelerate the plans already in place for
the Open Source project. Getting the 2.0 release done in the next few weeks, working on
long-standing features such as the Test framework and Flow Debugger.&lt;/p&gt;
&lt;p&gt;Alongside that we&#39;ll also be building a platform around Node-RED that will make it easier
to adopt at scale and integrate into existing enterprise environments.&lt;/p&gt;
&lt;p&gt;Node-RED remains a fully open source project, with its home at the OpenJS Foundation
and an open governance model that allows anyone to have a say in its development.&lt;/p&gt;
&lt;p&gt;Our goal is to incorporate as much of our work directly into the core project as possible. Where we do create closed-source components, we will work with the community to ensure the right APIs and extension points are in the core for all to benefit from.&lt;/p&gt;
&lt;p&gt;We will only be successful if the whole Node-RED community is successful.&lt;/p&gt;
&lt;p&gt;For me personally, this is a really exciting next step. I never expected to turn my little side project into a full-time job and now into a company.&lt;/p&gt;
&lt;h3 id=&quot;hiring-soon!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://flowfuse.com/blog/2021/04/first-deploy/#hiring-soon!&quot;&gt;Hiring soon!&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;ll be hiring soon - so keep an eye out if you&#39;re interesting in getting involved.&lt;/p&gt;
</content>
    </entry>
</feed>